.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来分别支持以协变和逆变的方式使用泛型。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
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)
    { }
}

  

 

posted @   #谭  阅读(153)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?
点击右上角即可分享
微信分享提示