C#里面的泛型(T),泛型类,泛型方法,泛型接口等简单解释

只是比较简单的解释,在实际使用中,如果遇到需要深入研究的场景,再翻阅相关资料深入研究下。

一、泛型T

这个T在实际使用中很常见,比如List<T>。其实我们还可以写成List<object>。但是这样写会有一个问题。比如我把一个int数据存入到一个List<object>集合中,int则会被自动转成object,当我们试图取取用这个int数据的时候,我们还要把object转成int。这期间有一个转换,int=》object=》int,这个转换涉及到拆箱和封箱操作,也就是引用类型到值类型或者值类型到引用过程转换的过程,这个是很耗时的。当数据量大的时候,这个对于代码的效率是有不可忽视的影响的。

同时,如果不小心把一个string类型存入到了这个List<object>中,系统是不会报错的。但是当要取用的时候,你也许开始没发现不小心存入了一个string类型,然后你想当然的认为它是一个int类型,把它转成了int,这个时候你的程序就要报错了。这也是一个问题。

这个时候使用List<object>的隐患就显现出来了。为了比较好的解决这两个问题,c#引入了T这个概念,因为在大部分场景下,我们的类型都是确定的,没必要用object。

当我们使用List<T>的时候,我们首先实例化一个List<T>,比如这样的代码:

List<string> list=new List<string>();

这个代码的意思是告诉list这个集合只能放string这个类型的数据,放其他类型的数据,编译器是会报错的。这样我们不难理解,T这个东西的作用,其实就是一个通用的容器,制造它的人开始不指定它是用来装什么的,而使用者在使用它的时候要告诉这个容器准备用来装什么,容器知道了用来装什么之后,后面所有存入操作,它都要检查一下你放的东西是不是开始指定的东西类型。

二、泛型方法

现在有一个需求,需要写一个方法,这个方法传入的参数可能是int型的,也可能是string型的。首先我们可以用方法的重载方案解决这个问题,比如下面两个重载方法:

        public void test(int param)
        { }
        public void test(string param)
        { }

但是这样的话如果支持的类型变多了,那么你需要写很多重载方法。如果只写一个重载方法,则可以写成

 public void test(object param) { }

但是这样写又出现object转成其他类型的问题,会带来效率损失。同时不检查类型,一旦传入了不支持的类型,可能会出问题。

现在把test方法改造一下,这样写:

 public void test<T>(T param){ }

这样写之后,使用的时候要求提前通知这个方法,你传入的是什么类型,即:

test<int>(10);

如果写成 test<int>("10");编译器就会报错。

这就是泛型方法。这里面我们省略了方法内部的实现,其实仔细想一下,如果要在这样的方法里面添加业务代码,似乎除了用于存放数据的集合之外,并没有多少场景需要这么写方法。没错,泛型这个东西最常用的应用场景就是数据集合。而List<T>就是一个存放各种数据的泛型类。

三、泛型类

上面的方法:public void test<T>(T param){ },我们可以尝试一下把<T>去掉,只写成public void test(T param){ }看看会发生什么。你会发现编译器会报错,那么我们再尝试一下在这个方法的类名上加上<T>,即写成:

 class TClass<T>
    {
        public void test(T param)
        { }
    }

你会发现,如果把<T>放到类名上,里面的方法就不需要加 <T>了,同时编译器也不会报错。这是一种比较简洁的写法。这个时候,TClass这个类就是泛型类,而它的构造方法,则和普通的类的构造方法的写法是一样的。当你要实例化这个类型的时候,必须告诉这个类型T代表哪个类型,之后,所有这个类里面被标识了T的地方,都是指你开始实例化指明的类型。比如test这个方法里面传入的param,一定要和你开始实例化这个类的时候指明的类型一致。再比如你写一个返回T的方法: public T returnTest() { },这个方法的返回值也必须是你实例化类时指明的类型。如果我们TClass改成List,把test改成Add,则方法变成了下面这样

 class List<T>
    {
        public void Add(T param)
        { }
    }

这不就是我们经常用的List<T>这个泛型集合吗。当然它的内部实现还有很多东西,这里我们不去关注。

四、有了泛型类的概念,泛型接口就很好理解了,给上面的TClass写一个接口进行规范:

 interface ITClass<T>
    {
        void test(T param);
    }

上面讲的TClass继承这个接口就可以了:

 class TClass<T> : ITClass<T>
    {
        public void test(T param)
        {
            throw new NotImplementedException();
        }
    }

猜你喜欢

转载自blog.csdn.net/dap769815768/article/details/81946506