日期:2013-01-29  浏览次数:20382 次



接泛型四
20.6.5语法歧义
在§20.9.3和§20.9.4中简单名字(simple-name)和成员访问(member-access)对于表达式来说容易引起语法歧义。例如,语句
F(G<A,B>(7));



可以被解释为对带有两个参数G<A和B>(7)的F的调用[1]。同样,它还能被解释为对带有一个参数的F的调用,这是一个对带有两个类型实参和一个正式参数的泛型方法G的调用。
如果表达式可以被解析为两种不同的有效方法,那么在“>”能被解析作为运算符的所有或一部分时,或者作为一个类型实参列表,那么紧随“>”之后的标记将会被检查。如果它是如下之一:
{ } ] > : ; , . ?
那么“>”被解析作为类型实参列表。否则“>”被解析作为一个运算符。
20.6.6对委托使用泛型方法
委托的实例可通过引用一个泛型方法的声明而创建。委托表达式确切的编译时处理,包括引用泛型方法的委托创建表达式,这在§20.9.6中进行了描述。
当通过委托调用一个泛型方法时,所使用的类型实参将在委托实例化时被确定。类型实参可以通过类型实参列表显式给定,或者通过类型推断(§20.6.4)而确定。如果采用类型推断,委托的参数类型将被用作推断处理过程的实参类型。委托的返回类型不用于推断。下面的例子展示了为一个委托实例化表达式提供类型实参的方法。
delegate int D(string s , int i)
delegate int E();
class X
{
public static T F<T>(string s ,T t){…}
public static T G<T>(){…}
static void Main()
{
D d1 = new D(F<int>); //ok,类型实参被显式给定
D d2 = new D(F); //ok,int作为类型实参而被推断
E e1 = new E(G<int>); //ok,类型实参被显式给定
E e2 = new E(G); //错误,不能从返回类型推断
}
}
在先前的例子中,非泛型委托类型使用泛型方法实例化。你也可以使用泛型方法创建一个构造委托类型的实例。在所有情形下,当委托实例被创建时,类型实参被给定或可以被推断,但委托被调用时,可以不用提供类型实参列表(§15.3)。


20.6.7非泛型属性、事件、索引器或运算符
属性、事件、索引器和运算符他们自身可以没有类型实参(尽管他们可以出现在泛型类中,并且可从一个封闭类中使用类型实参)。如果需要一个类似属性泛型的构件,取而代之的是你必须使用一个泛型方法。
20.7约束
泛型类型和方法声明可以可选的指定类型参数约束,这通过在声明中包含类型参数约束语句就可以做到。
type-parameter-constraints-clauses(类型参数约束语句:)
type-parameter-constraints-clause(类型参数约束语句)
type-parameter-constraints-clauses type-parameter-constraints-clause(类型参数约束语句 类型参数约束语句)
type-parameter-constraints-clause:(类型参数约束语句:)
where type-parameter : type-parameter-constraints(where 类型参数:类型参数约束)
type-parameter-constraints:(类型参数约束:)
class-constraint(类约束)
interface-constraints(接口约束)
constructor-constraint(构造函数约束)
class-constraint , interface-constraints(类约束,接口约束)
class-constraint , constructor-constraint(类约束,构造函数约束)
interface-constraints , constructor-constraint(接口约束,构造函数约束)
class-constraint , interface-constraints , constructor-constraint(类约束,接口约束,构造函数约束)
class-constraint:(类约束:)
class-type(类类型)
interface-constraint:(接口约束:)
interface-constraint(接口约束)
interface-constraints , interface-constraints(接口约束,接口约束)
interface-constraints:(接口约束:)
interface-type(接口类型)
constructor-constraint:(构造函数约束:)
new ( )
每个类型参数约束语句由标志where 紧接着类型参数的名字,紧接着冒号和类型参数的约束列表。对每个类型参数只能有一个where 语句,但where语句可以以任何顺序列出。与属性访问器中的get和set标志相似,where 语句不是关键字。


在where语句中给定的约束列表可以以这个顺序包含下列组件:一个单一的类约束、一个或多个接口约和构造函数约束new ()。
如果约束是一个类类型或者接口类型,这个类型指定类型参数必须支持的每个类型实参的最小“基类型”。无论什么时候使用一个构造类型或者泛型方法,在编译时对于类型实参的约束建会被检查。所提供的类型实参必须派生于或者实现那个类型参数个定的所有约束。
被指定作为类约束的类型必须遵循下面的规则。
该类型必须是一个类类型。
该类型必须是密封的(sealed)。
该类型不能是如下的类型:System.Array,System.Delegate,System.Enum,或者System.ValueType类型。
该类型不能是object。由于所有类型派生于object,如果容许的话这种约束将不会有什么作用。
至多,对于给定类型参数的约束可以是一个类类型。
作为接口约束而被指定的类型必须满足如下的规则。
该类型必须是一个接口类型。
在一个给定的where语句中相同的类型不能被指定多次。
在很多情况下,约束可以包含任何关联类型的类型参数或者方法声明作为构造类型的一部分,并且可以包括被声明的类型,但约束不能是一个单一的类型参数。
被指定作为类型参数约束的任何类或者接口类型,作为泛型类型或者被声明的方法,必须至少是可访问的(§10.5.4)。
如果一个类型参数的where 语句包括new()形式的构造函数约束,则使用new 运算符创建该类型(§20.8.2)的实例是可能的。用于带有一个构造函数约束的类型参数的任何类型实参必须有一个无参的构造函数(详细情形参看§20.7)。
下面是可能约束的例子
interface IPrintable
{
void Print();
}


interface IComparable<T>
{
int CompareTo(T value);
}
interface IKeyProvider<T>
{
T GetKey();
}
class Printer<T> where T:IPrintable{…}
class SortedList<T> where T: IComparable<T>{…}
class Dictionary<K,V>
where K:IComparable<K>
where: V: IPrintable,IKeyProvider<K>,new()
{

}

下面的例子是一个错误,因为它试图直接使用一个类型参数作为约束。
class Extend<T , U> where U:T{…}//错误
约束的类型参数类型的值可以被用于访问约束暗示的实例成员。在例子
interfa