`

泛 型

    博客分类:
  • CLR
 
阅读更多

面向对象的编程方式有一种好处是“代码重用”,泛型是CLR和编程语言提供的一种特殊机制,它支持另一种形式的重用,即“算法重用”。

比如,一个开发人员定义好一个算法,如排序、搜索、交换、比较或者转换等。但是,定义算法的开发人员并不设定该算法要操作什么数据类型;该算法可以应用于不同类型的对象。然后,另一个开发人员只要指定了算法要操作的具体数据类型,就可以开始使用这个现成的算法了。例如,可以用一个排序算法来操作Int32和String等类型的对象,或用一个比较算法来操作DateTime和Version等类型的对象。

CLR允许创建泛型引用类型、泛型值类型、泛型接口、泛型委托、泛型方法,但不允许创建泛型枚举类型。

一个常用的泛型引用类型 List<T>

这个泛型List类的设计者紧跟在类名后添加了一个<T>,表明它操作的是一个未指定的数据类型。

一个开发人员定义泛型类型或方法时,他为类型指定的任何变量(比如T)被称为类型参数。

另一个开发人员使用泛型类型或方法时,指定的具体数据类型被称为类型实参。 如List<DateTime>

 

泛型类型仍然是类型,所以它能从其他任何类型派生。使用一个泛型类型并指定类型实参时,实际是在CLR中定义一个新的类型对象,新的类型对象是从泛型类型派生自的那个类型派生的。换言之,由于List<T>是从Object派生的,所以List<String>、List<Guid>也是从Object派生的。类似的,DictionaryStringKey<TValue>派生自Dictionary<String,TValue>,所以DictionaryStringKey<Guid>派生自Dictionary<String,Guid>

 

泛型类型的同一性

有时一些开发人员可能如下使用泛型(以List<DateTime>为例),为的是简化代码:

internal sealed class DateTimeList:List<DateTime>{}

然后就可以像如下那样使用List<DateTime>了

DateTimeList dt=new DateTimeList();

但运行一下如下代码,我们就会发现这样做会丧失类型的同一性和相等性:

Boolean flag=(typeof(List<DateTime>)==typeof(DateTimeList));   结果是false

为了实现这种想法,C#提供了一种方法,如下:

using DateTimeList=System.Collections.Generic.List<System.DateTime>;

 

泛型方法

定义泛型类、结构、接口时,这些类型中定义的任何方法都可以引用由类型指定的一个类型参数。类型参数可以作为方法的参数,作为方法的返回值,或者作为方法内部定义的一个局部变量来使用。然而,CLR还允许一个方法指定它独有的类型参数,同样这些类型参数可用于参数、返回值或者局部变量。在下面的例子中,一个类型定义了一个类型参数,一个方法则定义了它自己的专用类型参数:

internal sealed class GenericType<T>{

  Private T m_value;

  public GenericType(T value){mvalue=value;}

  public TOutput Converter<TOutput>(){

     TOutput result=(TOutput)Convert.ChangeType(m_value,typeof(TOutput));

     return result;

  }

}

C#编译器支持在调用一个泛型方法时进行类型判断。这意味着编译器会在调用一个泛型方法时自动判断要使用的类型,而不需要指定方法的<T>的T的类型:

private void Swap<T>(ref T o1,ref T o2)

{

    T temp=o1;

    o1=o2;

    02=temp;

}

private void CallSwap()

{

   int32 n1=1,n2=2;

   Swap(ref n1,ref n2);  //调用Swap<Int32>

   string s1="Bill"; Object s2="Gates";

   Swap(ref s1,ref s2);  //错误,不能判断类型

}

执行类型判断时,C#使用变量的数据类型,而不是变量所引用的对象的类型,所以在第二个Swap调用中,变量S1是string类型,而变量S2是Object类型(尽管它所引用的对象时string类型),所以不能判断调用Swap<string>还是Swap<Object>

 

可验证性和约束

编译泛型代码时,C#编译器会对它进行分析,确保代码适用于已有或将来可能定义的任何类型,看下面代码:

private Boolean Method<T>(T o)

{

   T temp=o;

   Console.WriteLine(o.ToString());

   Boolean b=temp.Equals(0);

   return b;

}

这个方法适用于任何类型,因为所有类型都支持对Object类型定义的方法(这里是ToString和Equals)

再来看看如下代码:

private T Min<T>(T o1,T o2)

{

   if(o1.CompareTo(o2)<0) return o1;

   return o2;

}

C#编译器将不能编译上述代码,它不能保证这个方法适用于所有类型,因为许多类型都没有提供CompareTo方法。

如此的话泛型将没什么用,但幸好,编译器和CLR支持一个称为约束的机制,看下面新版本的Min方法:

public T Min<T>(T o1,To2) where T:IComparable<T>

{

   if(o1.CompareTo(o2)<0) return o1;

   return o2;

}

where关键字告诉编译器,为T指定的任何类型都必须实现同类型(T)的泛型IComparable接口

现在,编译器要负责保证类型实参符合指定的约束:

public void CallMin()

{

   string o1="Bill"; Object o2="Gates";

   Object oMin=Min<Object>(o1,o2);

}

上述代码将报错,因为Object没事实现IComparable<Object>接口,Object没有实现任何接口。、

CLR不允许基于类型参数名称或约束进行重载,只能基于类型参数个数来进行重载:

internal class AType{}    1

internal class AType<T>{}    2

internal class AType<T1,T2>{}    3

internal class AType<T> where T:IComparable<T>{}  与2冲突

internal class AType<T3,T4>{}  与3冲突

重写一个虚泛型方法时,重写的方法必须指定相同数量的类型参数,而且这些类型参数会继承在基类方法上指定的约束。事实上,根本不允许为重写方法的类型参数指定任何约束:

internal class Base

{

   public virtual void M<T1,T2> where T1:struct where T2:class{}

}

internal class Derived:Base

{

   public override void M<T3,T4> where T3:EventArgs where T4:class{}

   会报错,类型参数会继承在基类方法上指定的约束,不允许为重写方法的类型参数指定任何约束

}

主要约束

类型参数可以指定零个或一个主要约束,有两个特殊的主要约束:class和struct

class约束向编译器承诺一个指定的类型实参是引用类型:

internal class AType<T> where T:class

{

    public void M(){T temp=null;}   //所有引用类型的变量都能设为null

}

struct约束向编译器承诺一个指定的类型实参是值类型:

internal class AType<T> where T:struct

{

   public void M(){return new T();}  //所有值类型都隐藏一个公共无参构造器,而有的引用类型没有公共无参构造器

}

次要约束

次要约束又分两种,第一种用的比较多就是接口类型约束(可指定零个或多个)

指定一个接口类型约束时,是向编译器承诺一个指定的类型实参是实现了接口的一个类型,由于能指定多个接口约束,所以为类型实参指定的类型必须实现了所有接口约束(以及所有主要约束,如果指定了的话)

第二种用的比较少就是类型参数约束,意思是在指定的类型实参之间必须存在一个关系:

private List<TBase> Convert<T,TBase>(IList<T> list) where T:TBase{ ... }

以上方法指定了两个类型参数,其中T参数由TBase类型参数约束,意味着不管T指定什么类型实参,这个类型实参都必须兼容于为TBase指定的类型实参。

构造器约束

一个类型参数可以指定零个或一个构造器参数。指定构造器参数是向编译器承诺:一个指定的类型实参是实现了公共无参构造器的一个抽象类型:

internal class AType<T> where T:new()

{

    public T Menthod()

    {

        //所有值类型都隐式有一个公共无参构造器

        //约束要求指定的任何引用类型也要有一个公共无参构造器

        return new T();

    }

}

 

C#编译器允许使用default将一个泛型类型变量设为默认值:

private void SetIt<T>()

{

   T temp=default(T);

}

以上代码告诉C#编译器和CLR的JIT编译器,如果T是一个引用类型,就将temp设为null;如果T是值类型,就将temp设为0。

 

将一个泛型变量与null进行比较:

private void CompareIt<T>(T obj)

{

   if(obj==null){...}

}

由于T没有进行约束,如果T是一个值类型,...处的代码永远不会被执行

分享到:
评论

相关推荐

    泛 型 全 面 总 结

    泛型是Java编程中一个强大的特性,自JDK 1.5版本引入,旨在提高代码的安全性和效率。泛型的主要目的是在编译期间检查类型安全,并允许编译器生成更高效的字节码。它允许我们在定义集合、类、接口和方法时指定一种或...

    泛用型贴标机.rar

    《泛用型贴标机详解》 在工业自动化领域,贴标机是不可或缺的重要设备,其主要用于产品包装上的标签粘贴工作,提高了生产效率并确保了标签的质量。本篇文章将详细解析“泛用型贴标机”,并结合提供的“泛用型贴标机...

    泛用型贴标机全套图纸-几何模型

    【标题】"泛用型贴标机全套图纸-几何模型"揭示了这是一份关于通用贴标设备的设计图纸集,其中包含的是三维几何模型。在机械工程和自动化领域,这样的图纸是设计、制造和组装机械设备的基础,特别是对于贴标机这种...

    集团型多元化企业的数字化转型实践-泛地产行业大会员忠诚度解决方案-分享材料.pdf

    集团型多元化企业的数字化转型实践-泛地产行业大会员忠诚度解决方案

    带状疱疹及带状疱疹后神经痛.ppt

    特殊类型的带状疱疹包括眼带状疱疹和耳带状疱疹,以及各种不典型的类型,如顿挫型、不全型、大疱型、出血型、坏疽型、泛发型和播散型等。 神经系统并发症可能包括急性或慢性脑炎、脊髓炎、无菌性脑膜炎、多神经根炎...

    带状疱疹及带状疱疹后神经痛.ppt.ppt

    不同类型的特殊表现包括眼带状疱疹、耳带状疱疹和其他不典型的类型,如顿挫型、不全型、大疱型、出血型、坏疽型、泛发型、播散型等。带状疱疹还可能引发神经系统和内脏的并发症,如急性或慢性脑炎、脊髓炎、多神经根...

    儿童白癜风112例临床流行病学分析.docx

    在临床特征上,非节段性型白癜风是最常见的类型,占75.0%,其中肢端型占39.29%,泛发型占22.62%,散发型占38.10%。节段性型则占25.0%。发病部位以头、面、颈为主,这些部位分别占17.86%、16.07%和15.18%。此外,约...

    刚毛柽柳RING型E3泛素连接酶基因的克隆及表达分析

    刚毛柽柳RING型E3泛素连接酶基因的克隆及表达分析 ,张玉,张悦,E3泛素刚毛柽柳RING型E3泛素连接酶基因的克隆及表达分析连接酶是一个种类复杂的蛋白质家族,在对植物逆境胁迫的响应和生长发育等方�

    行业文档-设计装置-一种节能型泛光灯.zip

    在当前的环保与能源效率议题日益受到关注的背景下,"行业文档-设计装置-一种节能型泛光灯.zip" 提供了一个重要的知识焦点,即如何通过创新设计实现照明设备的节能化。这份压缩包内包含的"一种节能型泛光灯.pdf"详细...

    B25 泛用型贴标机.rar

    【标题】"B25 泛用型贴标机"所指的是一款设计用于各种不同形状和尺寸的产品贴标的机械设备。这种设备通常被广泛应用于食品、药品、化妆品、电子等行业,能够实现自动化、高效率的标签粘贴,提高生产线的生产速度和...

    C#和Labview资料

    ¨ … …… … … …1275.4.1 协变和抗变……………… 1285.4.2 泛型接口的协变………… 1295.4.3 泛型接口的抗变 ………… 1305.5 泛 型 结 构 ¨ … … … … … ¨ … ¨1315,6 泛 型方 法 … … … … …… … ...

    大数据-算法-122型异蕴涵泛三I算法及其应用研究.pdf

    《大数据-算法-122型异蕴涵泛三I算法及其应用研究》这篇博士论文主要探讨了在大数据处理和算法领域中,一种名为122型异蕴涵泛三I(Generalized Triple-I)算法的理论与应用。这篇论文由唐一鸣撰写,由刘晓平教授指导...

    泛目录5天上爱站权重7的源码思路解析

    最新新闻蜘蛛池站群源码-泛目录5天爱站权重7零距离泛目录:目前看到市面上权重最快的泛目录程序,程序目录结构见下面的图,程序来看有一些龙少站群的影子(泛域名站群) 首先通过快照源码分析,并无太多特殊之处,...

    rustprimer-v1.13-大家新年快乐.pdf

    泛 型 可 变 性 、 所 有 权 、 租 借 和 生 命 期 所 有 权 引 用 和 借 用 生 命 周 期 闭 包 闭 包 的 语 法 闭 包 的 实 现 闭 包 作 为 参 数 和 返 回 值 集 合 类 型 C o lle c t io n s 动 态 数 组 Ve c 哈...

    泛用型贴标机_三维3D设计图纸.zip

    泛用型贴标机_三维3D设计图纸.zip

    B25 泛用型贴标机 shop112483501.taobao.com.zip

    【标题】"B25 泛用型贴标机 shop112483501.taobao.com.zip" 暗示了我们讨论的主题是一款名为"B25 泛用型贴标机"的自动化设备,它可能在淘宝网上销售,店铺编号为"shop112483501"。这款贴标机设计用于各种应用场景,...

    行业文档-设计装置-一种节能型高频无极泛光灯.zip

    标题中的“行业文档-设计装置-一种节能型高频无极泛光灯.zip”表明这是一个关于照明设备设计的专题文档,具体聚焦在节能型高频无极泛光灯的设计上。无极泛光灯是一种先进的照明技术,它采用了不同于传统有源电子镇流...

Global site tag (gtag.js) - Google Analytics