一、泛型類
public class GenericStack<T>
{
private T[] stackArray;//泛型數組
private int currentPosition;//當前位置
private int count;//棧的數據容量
public GenericStack(int count)
{
this.count = count;
this.stackArray = new T[count];//初始化數組大小
this.currentPosition = 0;/當前位置從0開始
}
//入棧
public void Push(T item)
{
if(currentPosition >= count)
{
Console.WriteLine("當前棧空間已滿!");
}
else
{
this.stackArray[currentPosition] = item;
currentPosition++;
}
}
//出棧
public T Pop()
{
T result = this.stackArray[currentPosition-1];
currentPosition--;
return result ;
}
}
//調用
static void Main(string[] args)
{
GenericStack<int> stack1 = new GenericStack<int>(5);
stack1.Push(1);
stack1.Push(2);
stack1.Push(3);
stack1.Push(4);
stack1.Push(5);
stack1.Pop();
stack1.Pop();
stack1.Pop();
stack1.Pop();
stack1.Pop();
}
- 泛型好處:增加類型安全,編碼靈活性提高
- 常見泛型:泛型類 泛型方法
- 泛型類規範:
- public class 類型<T>{類的成員...}
- T僅爲佔位符,符合C#命名規則即可,表示一個通用的數據類型,在使用時用實際的類型替代
- 如果包含任意多個類型的參數,參數之間用逗號分隔,如GenericStack<T1,T2,T3>{...},所定義的各種類型參數,可以用做成員變量的類型,屬性,方法等返回值類型及方法參數...
二、泛型約束
//default關鍵字使用
public class GenericClass1<T1,T2>
{
private T1 obj1;
public GenericClass1()
{
//泛型使用的兩種錯誤
//obj1 = null;
//obj1 = new T1();//不能人爲假定某種類型,因爲這種類型也許沒有構造方法,也許是私有的
//解決方法
obj1 = default(T1);
}
}
//添加約束類型的泛型類
public class GenericClass2<T1,T2,T3>
where T2:class//類型必須爲引用類型
where T3:new()//在這個類中,類型必須有一個無參構造,且必須把這個約束放在最後
//其他類型-->基類類型 where T2:T1{} 表示T2必須與T1類型相同或繼承自T1
{
//產品列表
public List<T2> ProductList{get;set;}
//發行者
public T3 Publisher{get;set;}
public GenericClass2()
{
ProductList = new List<T2>();
Publisher = new T3();
}
//購買第幾個產品
public T2 BuyProduct(T1 num)
{
//return ProductList[num];//直接寫有錯誤,T1不一定爲int類型
dynamic index = num;//轉化爲動態類型
return ProductList[index];
}
}
//根據泛型類要求設計參數(實際開發時自行設計)
class Course
{
public string CourseName{get;set;}//課程名稱
public int Period{get;set;}//課程學習週期
}
class Teacher
{
public Teacher(){}
public string Name{get;set;}
public int Count{get;set;}//授課數量
}
static void Main(string[] args)
{
GenericClass2<int,Course,Teacher> myclass2 = new GenericClass2<int,Course,Teacher>();
myclass2.Publisher = new Teacher{Name = "",Count = 20};
myclass2.ProductList = new List<Course>()
{
new Course(){CourseName = "",Period = 6},
new Course(){CourseName = "",Period = 7}
}
Course myCourse = myclass2.BuyProduct(0);
Console.WriteLine("輸出======");
}
三、泛型方法
//實現四則運算
static T Add1<T>(T a,T b)
{
return a + b;//寫法錯誤
dynamic a1 = a;//動態類型僅在編譯期間存在,運行期間會被object類型替代(編譯時不考慮具體類型)
dynamic b1 = b;
return a1+b1;
}
static T Add2<T>(T a,T b)where T:struct
{
dynamic a1 = a;
dynamic b1 = b;
return a1+b1;
}
static T Sub<T>(T a,T b)where T:struct
{
dynamic a1 = a;
dynamic b1 = b;
return a1-b1;
}
static T Multiply<T>(T a,T b)where T:struct
{
dynamic a1 = a;
dynamic b1 = b;
return a1*b1;
}
static T Div<T>(T a,T b)where T:struct
{
dynamic a1 = a;
dynamic b1 = b;
return a1/b1;
}
//調用
static void Main(string[] args)
{
Add1(20,30);
Add2(10,20);
Sub(20.5,56);
Add2(20.5,5);
}
//實現一個數的求和
private static T Sum<T>(T a)where T : struct
{
int sum = default(T);
for(dynamic i=0;i<=a;i++)
{
sum+=i;
}
return sum;
}
四、泛型委託
static void Main(string[] args)
{
MyDeletegate<int> myDeletegate1 = Add;
MyDeletegate<double> myDeletegate2 = Sub;
//調用
myDeletegate1(10,20);
myDeletegate2(10.5,20.7);
}
//定義泛型委託
public deletegate T MyDeletegate(T a,T b);
static int Add(int a,int b)
{
return a+b;
}
static int Sub(double a,double b)
{
return a-b;
}
五、Action與Func
系統提供了沒有返回值和一個返回值的泛型委託
//最多可以有16個參數
public Action<int,int,int> myAction = (a1,a2,a3)=>
{
int resule = (a1+a2)*a3
Console.WriteLine(result);
}
///最後一個表示返回值類型
public Func<int,int,string> myFunc = (a1,a2)=>
{
int result = a1+a2;
return "返回值爲:"+result;
}
六、協變逆變
- 協變 out
- 某個返回值類型可以用它的子類類型替換,則這個類型支持協變,List不支持協變
- 應用,如:IEnumerable<父類> list= new List<子類>();
- 逆變 in
- 逆變是說某個《輸入類型》可以用它的《父類類型替換》
- 應用,如:Action<T>支持逆變,IEnumerable<子類> list= new List<父類>();
七、緩存
- 總結:正常情況下,如果創建一個靜態成員和靜態構造方法,在第一次使用的時候會初始化,後面再次使用永遠不會初始化
- 但是如果我們使用泛型類,當我們傳遞不同的類型時,靜態成員和靜態構造,還會在第一次執行
static void Main(string[] args)
{
CacheBaseGeneric<Student>.SaveData(new Student{name = "000"});
CacheBaseGeneric<Student>.GetData().Name;
CacheBaseGeneric<Teacher>.SaveData(new Student{name = "000"});
CacheBaseGeneric<Teacher>.GetData().Name;
//使用靜態構造方法,不同類型進入時先進行初始化,當該類型再次進入時則不進入構造方法,直接更新緩存
//總結:正常情況下,如果創建一個靜態成員和靜態構造方法,在第一次使用的時候會初始化,後面再次使用永遠不會初始化
//但是如果我們使用泛型類,當我們傳遞不同的類型時,靜態成員和靜態構造,還會在第一次執行
}
//基於泛型實現緩存:泛型類+靜態字段+靜態方法
//結論:泛型本質就是根據不同的數據類型,編譯成不同的類,下面可以實現高性能不同數據類型的數據緩存
public class CacheBaseGeneric<T>where T:class,new()
{
private static T tData = null;
//靜態構造方法
static CacheBaseGeneric()
{
Console.writeLine("靜態都在方法被調用,類型爲:"+typeof(T));
}
//保存數據
public static void SaveData(T data)
{
tData = data;
}
//獲取緩存數據
public static T GetData()
{
return tData;
}
}