一,什么是泛型
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()不需要些,从父类中继承过来了。