CLR Via C# 3rd 阅读摘要 -- Chapter 12 - Generics

Generics in the Framework Class Library

1. System.Collections.Generic、System.Collections.ObjectModel、System.Collections.Concurrent;

2. System.Array提供了很多静态的泛型方法,比如:AsReadOnly,BinarySearch,ConvertAll,Exists,Find,FindAll,FindIndex,FindLast,FindLastIndex,ForEach,IndexOf,LastIndexOf,Resize,Sort,TrueForAll。

Wintellect's Power Collections Library

1. Generic Collection Classes from Wintellect's Power Collections Library:

  • BigList<T>:有序的,当元素超过100时很有效;
  • Bag<T>:无序的,散列的,可重复;
  • OrderedBag<T>:有序的,可重复;
  • Set<T>:无序的,不可重复;
  • OrderedSet<T>:有序的,不可重复;
  • Deque<T>:双向队列;
  • OrderedDictionary<TKey, TValue>:键有序,一个键一个值;
  • MultiDictionary<TKey, TValue>:键无序,一个键对个值,键可重复,
  • OrderedMultiDictionary<TKey, TValue> :键有序,一个键多个值,键可重复。

Generics Infrastructure

1. 要支持泛型,.NET基础设施要做到 :

  • 创建新的IL指令;
  • 修改现有的元数据表格式;
  • 修改编程语言以支持新的语法;
  • 修改编译器以生成相应的IL指令和元数据表;
  • 修改JIT处理新的IL指令;
  • 创建新的反射成员使得开发者可以查询泛型参数的类型和成员信息; 
  • 修改调试器以调试泛型代码;
  • 修改IDE的IntelliSense支持显示泛型特性。

2. Open and Closed Types:

  • type objects:CLR创建的应用程序使用的每个类型的内部数据结构;
  • open type:一个有泛型类型参数的类型。CLR不允许构造任何open type的实例;
  • close type:所有的泛型参数都被实际类型传入替换。这时候CLR允许构造类型实例。

3. Generic Types and Inheritance,推荐:先定义一个普通的Node基类,然后定义一个泛型的TypedNode类(base Node);

4. using DateTimeList = System.Collections.Generic.List<System.DateTime>优于定义一个类internal sealed class DateTimeList : List<DateTime>;

5. 泛型,CLR会针对每一个方法和类型的组合生成本地代码,这会引起代码爆炸,使应用程序的工作集臃肿,并因此影响性能;

6. 针对代码爆炸,CLR所做的优化:

  • 如果一个方法使用一个实际的类型参数调用,之后总是以同样的类型参数调用,CLR针对这个方法/类型组合只编译一次代码;
  • CLR把所有的引用类型参数看成是同一个,所以这段代码就可以共享。注意值类型就不行了。 

Generic Interfaces

1. 对值类型,泛型的接口可以避免装箱操作。

Generic Delegates

1. 委托实际就是一个类,实现类型安全的回调。包含四个方法:构造器,Invoke,BeginInvoke,EndInvoke;

2. 推荐使用泛型的Action和Func。

Delegate and Interface Contravariant and Covariant Generic Type Arguments

1. Invariant,Contravariant,Covariant:

  • Invariant:泛型类型参数不能被改变; 
  • Contravariant(逆变):泛型类型参数可以从一个类变成一个从它继承的子类(in);
  • Covariant(协变):泛型类型参数可以从一个类变成该类的父类(out)。 

     public delegate TResult Func<in T, out TResult>(T arg); 

2. 使用带泛型参数并有返回值的委托时,推荐总是指定inout以表明逆变或协变。

Generic Methods

1. 当你定义一个泛型类、结构、接口之后,这个类型中的任何方法都可以引用该类型的类型参数;

2. 泛型方法与类型推导,在进行类型推导时,C#使用变量的数据类型,而不是该变量所指对象的实际类型;

3. 编译器总是优先使用显示匹配。

Generics and Other Members

1. 在C#中,properties、indexers、operator methods、constructors、finalizers本身不能有类型参数。

Verifiability and Constraints

1. public static T Min<T>(T 01, T 02)  where T : IComparable<T> { ... };

2. CLR不允许基于类型参数名称或约束的重载;

3. 当重载一个virtual的泛型方法时,重载的方法必须指定跟基类相同数量的类型参数,并且具有相同的约束;

4. 第一约束:

可以是一个没有密封的类的引用类型;

不能是这些特定类型:System.Object,System.Array,System.Delegate,System.MulticastDelegate,System.ValueType,System.Enum,System.Void;

两个特别的第一约束:class struct; 

编译器和CLR将System.Nullable<T>值类型作为一个特定类型,它不能满足struct的约束。 因为CLR想要禁止递归类型比如Nullable<Nullable<T>>。

5. 第二约束:where T :  TBase

6. 构造器约束:where T : new(); 

7. 其他的可验证性的问题:

  • 除非转换的类型跟约束中的类型相容,否则转换泛型变量到其他类型是非法的。但是可以先转换成Object或者使用as
  • 除非泛型类型约束成一个引用类型,否则设置泛型变量为null是非法的。但是可以用default(T)来设置默认值; 
  • 无论怎样,用==或者!=比较泛型变量和null都是非法的;
  • 如果泛型类型参数不是约束成引用类型,比较两个相同类型的泛型变量也是非法的。主要是非原生值类型不知道怎么处理==操作符;
  • 不能在泛型变量上使用运算符。 

本章小结

 本章讲了现代编程语言中的一个很重要的概念:泛型。泛型带来的好处:源代码保护;类型安全;更清爽的代码;更好的性能。解释了泛型(泛型类型,泛型接口,泛型委托,泛型方法)的实现机制和限制,然后介绍了如何对泛型类型进行验证和约束。

 

posted @ 2010-04-07 16:06  bengxia  阅读(269)  评论(0编辑  收藏  举报
无觅相关文章插件,快速提升流量