泛型
一,什么是泛型
1.这是一个Int类型的集合
public class IntList { int[] arr; int count; /// <summary> /// 获取已储存的元素的个数 /// </summary> public int Count { get { return count; } } public IntList(int length) { arr = new int[length]; } #region 1.0 向集合中 追加元素 +void Add(int ele) /// <summary> /// 向集合中 追加元素 /// </summary> /// <param name="ele"></param> public void Add(int ele) { //判断当前已添加元素的个数 是否 大于 数组的容量 if (count >= arr.Length) { //创建 2倍 的新数组 int[] arrNew = new int[arr.Length * 2]; //将arr 里的 数据 复制到 新数组中(从新数组的第0个位置开始存放) arr.CopyTo(arrNew, 0); //将新数组的引用 设置给 arr arr = arrNew; } //将元素 加入到 数组中 arr[count] = ele; //元素总个数 +1 count++; } #endregion #region 2.0 索引器 +int this[int index] public int this[int index] { get { if (index >= arr.Length) { throw new System.Exception("数组下标越界!"); } else { return arr[index]; } } set { if (index >= arr.Length) { throw new System.Exception("数组下标越界!"); } else { arr[index] = value; } } } #endregion
2.这是一个String类型集合
public class StringList { string[] arr; int count; /// <summary> /// 获取已储存的元素的个数 /// </summary> public int Count { get { return count; } } public StringList(int length) { arr = new string[length]; } #region 1.0 向集合中 追加元素 +void Add(int ele) /// <summary> /// 向集合中 追加元素 /// </summary> /// <param name="ele"></param> public void Add(string ele) { //判断当前已添加元素的个数 是否 大于 数组的容量 if (count >= arr.Length) { //创建 2倍 的新数组 string[] arrNew = new string[arr.Length * 2]; //将arr 里的 数据 复制到 新数组中(从新数组的第0个位置开始存放) arr.CopyTo(arrNew, 0); //将新数组的引用 设置给 arr arr = arrNew; } //将元素 加入到 数组中 arr[count] = ele; //元素总个数 +1 count++; } #endregion #region 2.0 索引器 +int this[int index] public string this[int index] { get { if (index >= arr.Length) { throw new System.Exception("数组下标越界!"); } else { return arr[index]; } } set { if (index >= arr.Length) { throw new System.Exception("数组下标越界!"); } else { arr[index] = value; } } } #endregion 当我们操作这些集合的时候
IntList intList = new IntList(3); intList.Add(9); intList.Add(19); intList.Add(59); for (int i = 0; i < intList.Count; i++) { Console.WriteLine(intList[i]); } StringList stringList = new StringList(3); stringList.Add("9a"); stringList.Add("19b"); stringList.Add("59c"); for (int i = 0; i < stringList.Count; i++) { Console.WriteLine(stringList[i]); }
会发现变得只是类型,这样重复的类型变换有什么办法解决了,这就需要用到泛型
/// <summary> /// 自定义泛型集合类,带泛型参数 /// </summary> /// <typeparam name="MyType">集合的元素类型</typeparam> public class MyGenericList<MyType>
{ MyType aValue; MyType[] arr; int count; //int a = MyType; #region 获取已储存的元素的个数 +int Count /// <summary> /// 获取已储存的元素的个数 /// </summary> public int Count { get { return count; } } #endregion public MyGenericList(int length) { arr = new MyType[length]; } #region 1.0 向集合中 追加元素 +void Add(MyType ele) /// <summary> /// 向集合中 追加元素 /// </summary> /// <param name="ele"></param> public void Add(MyType ele) { //判断当前已添加元素的个数 是否 大于 数组的容量 if (count >= arr.Length) { //创建 2倍 的新数组 MyType[] arrNew = new MyType[arr.Length * 2]; //将arr 里的 数据 复制到 新数组中(从新数组的第0个位置开始存放) arr.CopyTo(arrNew, 0); //将新数组的引用 设置给 arr arr = arrNew; } //将元素 加入到 数组中 arr[count] = ele; //元素总个数 +1 count++; } #endregion #region 2.0 索引器 +MyType this[int index] public MyType this[int index] { get { if (index >= arr.Length) { throw new System.Exception("数组下标越界!"); } else { return arr[index]; } } set { if (index >= arr.Length) { throw new System.Exception("数组下标越界!"); } else { arr[index] = value; } } } #endregion 现在调用则可以变成
MyGenericList<int> intList = new MyGenericList<int>(3); intList.Add(9); intList.Add(19); intList.Add(59); for (int i = 0; i < intList.Count; i++) { Console.WriteLine(intList[i]); }
string 类型的则可以
MyGenericList<string> stringList = new MyGenericList<string>(3); stringList.Add("9a"); stringList.Add("19b"); stringList.Add("59c"); for (int i = 0; i < stringList.Count; i++) { Console.WriteLine(stringList[i]); }
MyType只是相当于一个占位符,用的时候用具体的类型来替换即可。他只能是一个类型,不能是具体的值。
泛型是指的带类型参数的类,而不是类型参数本身。如public class MyList<T>{….}其中的MyList就是泛型,而T是类型参数。
泛型参数可以有多个,比如MyList<T,MyType>也是可以的
实例化一个引用类型的泛型,它在内存中分配的大小是一样的。
实例化一个值类型的泛型,它在内存中分配的大小是不一样的。
尽管如此,CLR还是为每个不同的类型参数创建了不同的泛型类版本。
二.泛型的继承
继承一个泛型类时,必须为其传递泛型参数!
public class Father<k,v>{}//父类
定义子类时直接为父类泛型参数赋值
public class Son:Father<int,string>
定义子类时把子类泛型参数赋给父类泛型参数 public class Son<w,y>:Father<int,string>
public class Son:Father<k,v> 这种是错误的,因为K,V不存在
三.泛型约束
public class MyGenericDog<T> where T:new()//约束 传给 T 的类 必须包含一个 无参的构造函数 { T t; public MyGenericDog() { t = new T(); } }
在使用时必须保证类有一个无参的构造函数
private void btnNewT_Click(object sender, EventArgs e) { MyGenericDog<LittleDog> list = new MyGenericDog<LittleDog>(); }
public class LittleDog { public LittleDog() { } public LittleDog(string str) { } }
四.用来约束泛型参数 必须是某个类 或者某个类的子类
class Dog { public void Shout(){} } class Cat { public void Walk(){} } class House<TPet,TPet2>where TPet:Dog where TPet2:Cat { public c(TPet p,TPet2 p2) { p1.Shout(); p2.Walk(); } }
1.一个泛型参数不允许多个基类约束,不能写成
class House<TPet,TPet2>where TPet:Dog where TPet:Cat 因为不可能既是狗,又是猫。
2.不能为密封类指定基类约束(string) 密封类即为私有类。即sealed这种不能继承的类。
3.也不能用nullable<T>
五.用来约束泛型参数必须是值类型或者引用类型
public struct A{} public class B{} public class C<T> where T:struct 值类型 { } public class C2<T> where T:class 引用类型 { } 比如上面的如果使用c<person>就会报错
六.泛型方法
public void Test<k>() where k:new() { }
K可以用在三个地方:
1.参数
public void Test<k>(k a) { }
2.可以在方法体内用到
public void Test<k>() where k:new() { k k1=new k(); }
3.可以当返回值
public K Test<k>() where k:new() { return k; }
七.泛型方法的重载
void sayA()
{
}
void sayA<T>() { } void sayA<K>() { }
在使用时可以看到智能提示出现两个方法say,say<>说明他们不构成重载
void sayA<T>() { } void sayA<K>() { }
这样是不行的,因为泛型方法只是个占位符,编译器会认为是同一个方法
八.泛型方法重写
子类当中约束where k:class是不能在子类中重写。而where k:new()不需要些,从父类中继承过来了。