.net基础—泛型
泛型
泛型在 .NET Framework 2.0 中首次引入,它本质上是一个“代码模板”,可让开发者定义类型安全数据结构,无需处理实际数据类型。 例如,List<T> 是一个可以声明的泛型集合,可与 List<int>、List<string> 或 List<Person> 等任何类型结合使用。
为方便理解泛型的作用,让我们看看添加泛型之前和之后的一个特定类:ArrayList。 在 .NET Framework 1.0 中,ArrayList 元素属于 Object 类型。 添加到集合的任何元素都会以静默方式转换为 Object。 从列表读取元素时,会发生相同的情况。 此过程称为装箱和取消装箱,它会影响性能。 但除了性能之外,在编译时无法确定列表中的数据的类型,这会形成一些脆弱的代码。 泛型解决了此问题,它可以定义每个列表实例将要包含的数据类型。 例如,只能将整数添加到 List<int>,只能将人员添加到 List<Person>。
泛型还可以在运行时使用。 运行时知道你要使用的数据结构类型,并可以更高效地将数据结构存储在内存中。
泛型的性能
通过执行一亿次三种不同类型方法:确定参数类型的方法、Object参数类型的方法、 泛型参数类型的方法,来看一下它们的耗时情况。
1 class Program 2 { 3 static void Main(string[] args) 4 { 5 int testVal = 123; 6 long commonSecond = 0; 7 long objectSecond = 0; 8 long genericSecond = 0; 9 10 { 11 // 调用确定参数类型的方法的耗时 12 Stopwatch watch = new Stopwatch(); 13 watch.Start(); 14 for (int i = 0; i < 100000000; i++) 15 { 16 ShowInt(testVal); 17 } 18 watch.Stop(); 19 commonSecond = watch.ElapsedMilliseconds; 20 } 21 { 22 // 调用Object参数类型的方法的耗时 23 Stopwatch watch = new Stopwatch(); 24 watch.Start(); 25 for (int i = 0; i < 100000000; i++) 26 { 27 ShowObject(testVal); 28 } 29 watch.Stop(); 30 objectSecond = watch.ElapsedMilliseconds; 31 } 32 { 33 //调用泛型参数类型的方法的耗时 34 Stopwatch watch = new Stopwatch(); 35 watch.Start(); 36 for (int i = 0; i < 100000000; i++) 37 { 38 Show<int>(testVal); 39 } 40 watch.Stop(); 41 genericSecond = watch.ElapsedMilliseconds; 42 } 43 Console.WriteLine("commonSecond = {0} \n objectSecond = {1} \n genericSecond = {2} ", 44 commonSecond, objectSecond, genericSecond); 45 46 } 47 48 /// <summary> 49 /// 确定参数类型的方法 50 /// </summary> 51 /// <param name="valParam"></param> 52 private static void ShowInt(int valParam) 53 { 54 55 } 56 /// <summary> 57 /// Object参数类型的方法(类型不确定通过用obj 来实现通用) 58 /// </summary> 59 private static void ShowObject(int objParam) 60 { 61 62 } 63 /// <summary> 64 /// 泛型参数类型的方法 65 /// </summary> 66 private static void Show<T>(int tParam) 67 { 68 69 } 70 71 }
上面代码的执行效果:

通过上图可以得出:确定参数类型的方法和 泛型参数类型的方法相差不是很大,Object参数类型的方法的方法性能最差,Object慢的原因是多了一个装箱操作。
协变逆变
在C# 4.0之前,所有的泛型类型都是不变量——即不支持将一个泛型类型替换为另一个泛型类型,即使它们之间拥有继承关系,简而言之,在C# 4.0之前的泛型都是不支持协变和逆变的。
C# 4.0通过两个关键字:out和in来分别支持以协变和逆变的方式使用泛型。
class Program
{
static void Main(string[] args)
{
List<Bird> birdList1 = new List<Bird>();
// vs提示错误
//List<Bird> birdList2 = new List<Sparrow>();
List<Bird> birdList3 = new List<Sparrow>().Select(c => (Bird)c).ToList();
//协变 IEnumerable<Bird>既可以接受父类也可以接受子类
IEnumerable<Bird> birdList4 = new List<Bird>();
IEnumerable<Bird> birdList5 = new List<Sparrow>();
//逆变 ICustomerListIn<Sparrow>既可以接受父类也可以接受子类
ICustomerListIn<Sparrow> customerList1 = new CustomerListIn<Bird>();
ICustomerListIn<Sparrow> customerList2 = new CustomerListIn<Sparrow>();
}
}
class Bird
{
}
class Sparrow : Bird
{
}
/// <summary>
/// out 协变 只能是返回结果
/// </summary>
/// <typeparam name="T"></typeparam>
public interface ICustomerListOut<out T>
{
T Get();
}
public class CustomerListOut<T> : ICustomerListOut<T>
{
public T Get()
{
return default(T);
}
}
/// <summary>
/// in 逆变 只能是参数
/// </summary>
/// <typeparam name="T"></typeparam>
public interface ICustomerListIn<in T>
{
void Show(T t);
}
public class CustomerListIn<T> : ICustomerListIn<T>
{
public void Show(T t)
{ }
}

浙公网安备 33010602011771号