博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
泛型/泛型约束/协变逆变
阅读量:7281 次
发布时间:2019-06-30

本文共 5284 字,大约阅读时间需要 17 分钟。

泛型

泛型允许你在编译时实现类型安全。它们允许你创建一个数据结构而不限于一特定的数据类型。然而,当使用该数据结构时,编译器保证它使用的类型与类型安全是相一致的。泛型提供了类型安全,但是没有造成任何性能损失和代码臃肿

通过参数化类型来实现在同一份代码上操作多种数据类型,利用“参数化类型”将类型抽象化,从而实现灵活的复用。每个集合的详细规范可以在System.Collection.Generic名称空间下找到

泛型的适用场景

打印int,string类型参数

class Print    {        public static void PrintInt(int parameter)        {            Console.WriteLine("This is {0},parameter={1},type={2}",               typeof(Print).Name, parameter.GetType().Name, parameter);        }        public static void PrintString(string parameter)        {            Console.WriteLine("This is {0},parameter={1},type={2}",               typeof(Print).Name, parameter.GetType().Name, parameter);        }    }

如果需要继续添加打印double或者其他类型参数就需要继续添加方法;使用继承object类处理,因为object是所有类型的基类

class Print    {        public static void PrintObject(object parameter)        {            Console.WriteLine("This is {0},parameter={1},type={2}",               typeof(Print).Name, parameter.GetType().Name, parameter);        }    }

 这么做看起来解决了这个问题,考虑下面的情形(没有实际意义,仅做学习参考)

class Print    {        public static void PrintObject(object parameter)        {            int str = 0;            str += (int)parameter;            Console.WriteLine("This is {0},parameter={1},type={2}",               typeof(Print).Name, parameter.GetType().Name, str);        }    }
class Program    {        static void Main(string[] args)        {            Print.PrintObject(1);            Print.PrintObject(true);            Console.ReadKey();        }    }

再比如这样

ArrayList list = new ArrayList();            list.Add(50);            list.Add("哈哈");             //如果使用整数对象来使用foreach语句进行遍历的话,当编译器接受到代码,但是因为集合中的所有元素都不是整数,所以会导致运行时异常            foreach (int i in list)            {                Console.WriteLine(i);            }

当传值为int类型1时,代码是可以正常运行的,但传值为true就会造成类型转换错误,并且编译时并没有获取到这个错误,这说明当前的方法并不是类型安全的;而且使用object类会造成大量的装箱/拆箱操作,这对性能也有很大损耗

这种时候就可以考虑使用泛型来实现

泛型方法

class Print    {        ///         /// Object方法处理打印各种类型值        ///         ///         public static void PrintObject(object parameter)        {            Console.WriteLine("This is {0},parameter={1},type={2}",               typeof(Print).Name, parameter.GetType().Name, parameter);        }                ///         /// 泛型方法处理打印各种类型值        ///         /// 
/// public static void PrintT
(T tParameter) { Console.WriteLine("This is {0},parameter={1},type={2}", typeof(Print).Name, tParameter.GetType().Name, tParameter); } }

 泛型类

class Program    {        static void Main(string[] args)        {            Print
iPrint = new Print
(); iPrint.t = 123; Print
sPrint = new Print
(); sPrint.t = "123"; Console.ReadKey(); } } class Print
{ public T t; }

 泛型接口

interface IPrint
{ T GetT(T t); }

泛型委托

public delegate void Print
(T t);

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

Print
iPrint = new Print
();//这里的类型是int

如果存在继承并且子类也是泛型的,那么继承的时候可以不指定具体类型

class Print
{ public T t; } //这里继承时没有指定泛型类型 class ConsolePrint
: Print
{ }

同上,类实现泛型接口也是如此

泛型约束

 T:类 类型参数必须是引用类型,包括任何类、接口、委托或数组类型
 T:结构 类型参数必须是值类型。可以指定除 Nullable 以外的任何值类型
 T:new() 类型参数必须具有无参数的公共构造函数。当与其他约束一起使用时,new() 约束必须最后指定
 T:<基类名> 类型参数必须是指定的基类或派生自指定的基类
 T:<接口名称> 类型参数必须是指定的接口或实现指定的接口。可以指定多个接口约束。约束接口也可以是泛型的
T1:T2 类型T1派生自泛型类型T2,该约束也被称为裸类型约束
class Person    {        public static void PintSayHello()        {        }    }    interface ISport    {        void Sport();    }    ///     /// 约束T必须是Person类型或者是Person的子类并且实现了ISport接口且T类型中必须有无参构造函数    ///     /// 
class Show
where T : Person, ISport, new() { } ///
/// 约束T必须是引用类型并且实现了ISport接口且T类型中必须有无参构造函数 /// ///
class Show2
where T : class, ISport, new() { } ///
/// 约束T必须是值类型并且实现了ISport接口 /// ///
class Show3
where T : struct, ISport { }

 注意:泛型约束可以同时约束多个,有多个泛型约束时,new()约束一定是在最后

泛型的协变和逆变

这里暂时理解不是很透彻,随后继续学习,先往下看. 参考

几个问题:

class Print    {        public static int Sum(int a, int b)        {            return a + b;        }        public static string Sum(string a, string b)        {            return a + b;        }    }

调用

Console.WriteLine(Print.Sum(1, 2)); Console.WriteLine(Print.Sum("1", "2"));

泛型适用与不同数据类型共享一组功能时,所以定义泛型方法

public static T Sum
(T t1, T t2) { return t1 + t2; }

错误:运算符+无法适用于T类型和T类型的操作数,看到下面一种办法

//添加泛型约束,T类型必须是值类型 public static T Sum
(T t1, T t2) where T:struct { dynamic d1 = t1; dynamic d2 = t2; return d1 + d2; } 

调用时:

   //这里可以不指定类型,由编译器推断     Console.WriteLine(Print.Sum
(1, 2)); Console.WriteLine(Print.Sum
(1.2, 1.3));

到现在为止是可以正常调用的,但是如果出现类似下面的情况,就会产生运行错误(编译时没有错误)

Console.WriteLine(Print.Sum(false, true)); Console.WriteLine(Print.Sum(new A(), new A()));//这里的A是一个结构类型

还没有看到比较信服的说法,如果有朋友知道,望请告知

参考:

 

转载于:https://www.cnblogs.com/GnailGnepGnaw/p/10606944.html

你可能感兴趣的文章
Heroku免费版限制
查看>>
Struts2拦截器
查看>>
jQuery的$.extend和$.fn.extend作用及区别
查看>>
[C#] async 的三大返回类型
查看>>
数据结构之---C语言实现图的邻接表存储表示
查看>>
Node.js 把图片流送到客户端
查看>>
Android P 功能和 API
查看>>
php --with-mysql=mysqlnd
查看>>
登录(ajax提交数据和后台校验)
查看>>
谷歌中国的第一款产品“猜画小歌”
查看>>
HTTP 错误 500.19 - Internal Server Error
查看>>
序列起始值修改
查看>>
蓝点中文_Linux2.0 实验三 用户组管理
查看>>
php表单在提交之后再后退,表单的内容默认是被清空的
查看>>
重写方法Android中的HttpsURLConnection连接
查看>>
linux(ubuntu) 查看系统设备信息
查看>>
hdu4467 Graph
查看>>
C#中byte类型转换为double类型
查看>>
有意思的网站
查看>>
max3232
查看>>