C#基础知识点总结(四)- 泛型

1. 泛型概述

泛型最大的优点就是做到了通用。在编程程序时,经常会遇到功能非常相似的模块,只是它们处理的数据不一样。泛型可以用同一个方法来处理传入不同类型的参数

        //下面三个方法把参数类型写定了

        public static void ShowIntData(int a, int b)
        {
            Console.WriteLine($"{a},{b}");
        }
        public static void ShowDateData(DateTime a, DateTime b)
        {
            Console.WriteLine($"{a},{b}");
        }
        public static void ShowStringData(string a, string b)
        {
            Console.WriteLine($"{a},{b}");
        }
        //上面三个方法除了传入的参数不同外,其里面实现的功能都是一样的
        //使用继承,也就是int, string, datetime类都继承自object这个一切类型的父类
        //使用obejct类型进行转换为int, string,datetime时会有装箱和拆箱,会损耗程序的性能
        public static void ShowDate(object a, object b)
        {
            Console.WriteLine($"{a},{b}");
        }
        //泛型方法,解决上述所有问题
        //在调用ShowData<T>方法时,T要传入具体的参数类型,比如int
        public static void ShowData<T>(T a, T b )
        {
            Console.WriteLine($"{a},{b}");
        }

            int a = 3, b = 5;
            ShowData<int>(a, b);

            PhoneCustomer phoneone = new PhoneCustomer()
            {
                FirstName = "aa",
                Age = 1
            };
            PhoneCustomer phonetwo = new PhoneCustomer()
            {
                FirstName = "bb",
                Age = 2
            };
            //T都是PhoneCustomer类型,T类型要统一
            ShowData<PhoneCustomer>(phoneone, phonetwo);

1. 类型参数T是在实例化泛型类型的一个变量时指定的特定类型的占位符,它在使用时必须传入具体的参数类型,比如int, 自定义person类等

2. 泛型是延迟声明的:即定义的时候没有指定具体的参数类型,把参数类型的声明推迟到了调用的时候才指定参数类型。 延迟思想在程序架构设计的时候很受欢迎。例如:分布式缓存队列、EF的延迟加载等等

3. 泛型方法的性能最高,其次是普通方法,object方法的性能最低

1.1 泛型性能

泛型的一个主要优点是性能,避免了装箱和拆箱。而对值类型使用非泛型集合类时,使用装箱和拆箱。拆箱和装箱性能损失较大

装箱:值类型转换为引用类型

拆箱:引用类型转换为值类型,需要使用类型强制转换运算符

            var list = new ArrayList();
            //装箱
            list.Add(44);
            //拆箱,使用了类型强制转换运算符
            int arr = (int)list[0];

1.2 类型安全

泛型另一个特性是类型安全

            //泛型类List<T>,这里T定义为int,所以List中只能添加Int类型的数据,添加string类型的数据,会报错
            var list = new List<int>();
            list.Add(33);
            //编译器报错
            list.Add("baab");

2. 创建泛型类(接口,方法)

方法可以是泛型的,类也可以是泛型的,接口也可以是泛型的

1. 泛型在声明的时候可以不指定具体的类型,但是在使用的时候必须指定具体类型

2. 子类也是泛型的,那么继承的时候可以不指定具体类型

            //泛型类
            public class GenericClass<T>
            {
                public T _T;
            }
            // T是int类型
            GenericClass<int> genericInt = new GenericClass<int>();
            genericInt._T = 123;
            // T是string类型
            GenericClass<string> genericString = new GenericClass<string>();
            genericString._T = "123";

    /// <summary>
    /// 泛型接口
    /// </summary>
    public interface IGenericInterface<T>
    {
        //泛型类型的返回值
        T GetT(T t);
    }

        //泛型方法
        //T,K,S可以分别是三种不同的类型,比如int,string,double
        public static void ShowData<T, K, S>(T a, K k, S s)
        {
            Console.WriteLine($"{a},{k},{s}");
        }
public delegate void SayHi<T>(T t);//泛型委托

3. 泛型类的功能

3.1 默认值(default)

1. 不能把null赋予泛型类型,但是可以用default,将null赋予引用类型,将0赋予值类型

    public T GetDocument()
    {
        T doc = default(T);
        return doc;
    }

3.2 约束(where)

泛型类需要调用泛型类型中的方法,就必须添加约束。所谓的泛型约束,实际上就是约束的类型T。使T必须遵循一定的规则。比如T必须继承自某个类,或者T必须实现某个接口等等。

约束s说明
T:结构类型参数必须是值类型(比如:struct/int/double/bool/enum等)
T:类类型参数必须是引用类型(数组/类/接口/委托/object/字符串等);这一点也适用于任何类、接口、委托或数组类型。
T:new()类型参数必须具有无参数的公共构造函数。 当与其他约束一起使用时,new() 约束必须最后指定。
T:<基类名>类型参数必须是指定的基类或派生自指定的基类。
T:<接口名称>类型参数必须是指定的接口或实现指定的接口。 可以指定多个接口约束。 约束接口也可以是泛型的。
    //指定泛型参数为值类型
    public class MyListVlue<T> where T : struct
    {
        //
    }
    //指定泛型参数为引用类型
    public class MyListClass<T> where T : class
    {
        //
    }
    // 指定泛型参数有无参的公共的构造函数
    public class MyListBase<T> where T : new()
    {
        //
    }
    //指定泛型参数必须派生于指定基类, 要调用MyListHer<T>方法,必须派生于SeniorAnimal的类才能调用
    public class MyListHer<T> where T : SeniorAnimal
    {
      //
    }
    //指定泛型参数 必须实现指定接口,要调用MyListInterface<T>方法,必须继承IBankAccount接口的类才能调用
    public class MyListInterface<T> where T : IBankAccount
    {
        //
    }
    //泛型约束也可以同时约束多个
    public static void Show<T>(T tParameter)
            where T : People, ISports, IWork, new()
    {
        //
    }
     //泛型方法
     //T,K,S可以分别是三种不同的类型,比如int,string,double
     public static void ShowData<T, K, S>(T a, K k, S s)
        where T:struct
        where K:class
        where S:new()
     {
         //
     }

1. 基类(约束T必须是自定义的People类型或者是People的子类)约束时,基类不能是密封类,即不能是sealed类。sealed类表示该类不能被继承,在这里用作约束就无任何意义,因为sealed类没有子类

2. 有多个泛型约束时,new()约束一定是在最后

4. 泛型的协变和逆变

只能放在接口或者委托的泛型参数前面,out 协变covariant,用来修饰返回值;in逆变contravariant,用来修饰传入参数。

 

 

 

 

 

 

 

代码解释:

1. Teacher是People的子类

4.1 协变

使用了协变以后,左边声明的是基类,右边可以声明基类或者基类的子类。

更详细可看C#泛型详解 - .NET开发菜鸟 - 博客园 (cnblogs.com)

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值