一、泛型的诞生
在C#1 中我们还没有泛型的时候我们收集数据通常需要使用到数组,或者使用封装好的数组集合Hashtable ArrayList。
举个例子:
我们在读取文件的时候就会需要一个数组来储存读取的数据的内容 但我们并不知数据的具体长度也就无法在声明的时候附上准确的数组长度。
这时我们可以使用一种较为繁琐的方法 就是声明一个数组,如果当前的数组已经被填满,那么将当前数组的数据复制到一个更加大的数组当中 ,直到数组没有被填满就将当前数组的实际有效内容复制到一个正好大小的数组当中。
/// <summary>/// 输出数组中的所有元素/// </summary>/// <param name="arrayList"></param>static void WrileArray(System.Collections.ArrayList arrayList){foreach (int item in arrayList){System.Console.WriteLine(item);}}
调用:
static void Main(){WrileArray(new System.Collections.ArrayList() { 1, 5, 7, 8, 9 });System.Console.ReadLine();}
提示: 在我们集合中如果一直是int数据当然不会发生任何问题,但一旦我们的集合当中有非int类型的数据则就会抛出异常。
这种情况下我们也可以自定义一个集合类指定集合只能接收某种类型。
举个例子:
class MYcollections : System.Collections.CollectionBase
{public void Add(int str) => List.Add(str);public void Remove(int Itemm) => List.Remove(Itemm);public int MycollectionsCount => List.Count;
}
使用方式:
static void Main(){WrileArray(new MYcollections() { 1, 5, 7, 8, 9 });System.Console.ReadLine();}
注意:这时候您在想添加非int类型的数组则不会通过编译器,但上述方法还是有点繁琐,于是我门C#2当中就推出了泛型这一概念。可以完美解决上述问题。
二、泛型
使用泛型完成上述一致的效果:
static void Main(){WrileArray<int>(new List<int> { 1, 5, 7, 8, 9 });System.Console.ReadLine();}/// <summary>/// 输出数组中的所有元素/// </summary>/// <param name="arrayList"></param>static void WrileArray<T>(List<T> arrayList){foreach (T item in arrayList){System.Console.WriteLine(item);}}
示例解释:
我们创建了一个List的泛型类型作为WriteAay方法的参数,其中T泛型参数的标识符代表可以为任何类型,在我们传递了类型实参的时候,泛型方法中的类型形参类型都将是类型实参的类型,如我们传递了int类型那么泛型方法当中的所有这个类型形参都将为int类型。
类型形参 类型实参
提示:在泛型方法中,可以使用泛型类型参数作为其他泛型类或方法的类型实参。这可以使得泛型方法更加灵活和通用。如下图所示:
泛型度(arrity):指泛型类型当中的泛型形参的个数
泛型的适用范围:
以下成员是不可能声明为泛型:字段、属性、索引器、构造器、事件、终结器。判断一个是否为泛型的唯一标准是看当前的泛型形参是否首次声明。
类型推断:
在泛型类型中,对类型形参传输了类型实参的情况下。当前对应的类型形参,将直接为当前类型也就不在需要再次声明当前的类型形参的类型。
类型约束:
文章:C#泛型(详解)-CSDN博客
default运算符:
default关键字可以获取当前数据类型的默认数据。如果是可空类型默认值则为Null。如果是非空类型则是类型对应的0值。
default运算符可以用于类型形参、类型实参、用于泛型也涉及泛型形参、用于泛型也涉及泛型实参
1 对于类型形参:当在泛型类、泛型方法或泛型委托中使用泛型形参时,可以使用 default
运算符得到类型参数的默认值。例如:
T defaultValue = default(T);
2 对于类型实参:default
运算符可以用于对特定类型的实参获取默认值。例如:
int defaultValue = default(int);
typeof 运算符:
typeof运算符返回的类型是Type类型,可以用于泛型。使用Type类提供的一些方法和属性我们可以在泛型当中进行类型转换。
以下是 System.Type
类提供的一些常用方法和属性:
-
GetType()
: 返回当前对象的System.Type
。 -
IsAssignableFrom(Type c)
: 检查当前类型是否可以从指定的类型分配。 -
IsInstanceOfType(object o)
: 检查当前类型是否是给定对象的实例。 -
GetMethod(string name, Type[] parameters)
: 获取指定名称和参数类型的方法。 -
GetMethods()
: 获取该类型中定义的所有公共方法。 -
GetProperty(string name)
: 获取指定名称的属性。 -
GetProperties()
: 获取该类型中定义的所有公共属性。 -
IsGenericType
: 检查当前类型是否为泛型类型。 -
IsGenericTypeDefinition
: 检查当前类型是否为泛型类型的定义。 -
MakeGenericType(params Type[] typeArguments)
: 创建一个封闭的泛型类型,通过将类型参数替换为指定的类型参数数组。
下面是一个示例,演示了如何在泛型中使用 System.Type
类进行类型转换和操作:
public class MyGenericClass<T>
{public void PrintTypeInformation(){Type type = typeof(T);Console.WriteLine("Type name: " + type.Name);Console.WriteLine("Is generic type definition: " + type.IsGenericTypeDefinition);Console.WriteLine("Is generic type: " + type.IsGenericType);if (type.IsGenericType){Type[] typeArguments = type.GetGenericArguments();Console.WriteLine("Type arguments: ");foreach (Type argument in typeArguments){Console.WriteLine("- " + argument.Name);}Type closedType = type.MakeGenericType(typeof(string));Console.WriteLine("Closed type: " + closedType.Name);}}
}
示例解释:
我们定义了一个名为
MyGenericClass
的泛型类,通过使用System.Type
类的方法和属性,在PrintTypeInformation
方法中打印了与泛型相关的类型信息。在这个例子中,我们展示了如何获取泛型参数的类型信息,并使用MakeGenericType
方法创建了一个封闭的泛型类型,将类型参数替换为string
类型。
(typeof(MyGenericClass<int>), obj.GetType());
提示:当前的效果是一致的。
1 typeof(T)当前表达式时返回的当前类型形参T对应的类型实参的Type。它返回值永远是一个封闭的,已构造的类型。
举个例子:
public class Pair<T>
{public T First { get; set; }public T Second { get; set; }public Pair(T first, T second){First = first;Second = second;}
}
现在,我们可以创建不同类型的封闭的已构造类型,比如:
Pair<int> intPair = new Pair<int>(10, 20);
Pair<string> stringPair = new Pair<string>("Hello", "World");
Pair<bool> boolPair = new Pair<bool>(true, false);
示例解释:
在这些示例中,
intPair
是一个封闭的已构造类型,Pair<int>
是通过将泛型类型参数T
替换为int
而创建的具体类型。同样,stringPair
和boolPair
分别是Pair<string>
和Pair<bool>
的封闭的已构造类型。
2 typeof(List<>)当前的表达式看似好像是缺少参数但实际上是可以编译的。对于泛型度为1的这么写,对应泛型度为2的typeof(List<,>)泛型度为3的typeof(List<,,,>)。注意当前表达式只在typeof运算符中有效。
举个例子:
System.Console.WriteLine(typeof(List<>));System.Console.ReadLine();