C# 2.0 Specification(泛型六)
来源:互联网 发布:js如何重新加载页面 编辑:程序博客网 时间:2024/05/20 10:56
<script type="text/javascript"><!--google_ad_client = "pub-2947489232296736";/* 728x15, 创建于 08-4-23MSDN */google_ad_slot = "3624277373";google_ad_width = 728;google_ad_height = 15;//--></script><script type="text/javascript"src="http://pagead2.googlesyndication.com/pagead/show_ads.js"></script>
通过创建一个类型参数被绑定到的运行时类型的实例,并调用该类型的默认构造函数,就可以执行对象创建表达式。运行时类型可以是引用或者值类型。
下面的例子检查一个非约束类型参数类型的实参是否是null。class C<T>{ void F(T x){if(x==null) thow new ArgumentNullException();…}} 即使是T可以表示一个值类型,x==null构件也是允许的,并且当T是值类型时,其结果被简单的定义为false。
u 否则,如果I是T中可访问成员的名字,并且如果那个成员是一个带有匹配类型参数数量的类型,那么命名空间或类型名字引用类型T.I或者类型T.I<A1,…AN>。注意当确定命名空间或类型名字的意义时,无类型成员(常数、字段、方法、属性、索引器、运算符、实例构造函数、析构函数和静态构造函数)和带有不同数量的类型参数成员将会被忽略。- 否则,对于在以命名空间或类型名字出现的命名空间开始的每个命名空间N,并继续使用每个封闭命名空间(如果有的话),然后以全局命名空间结束,下面的步骤将会被计算,直到该实体被定位。u 如果I 是在N中的命名空间中的名字,并且没有指定类型实参列表,那么命名空间或类型名字引用该个命名空间。u 否则,如果I是在N中带有匹配类型参数数量的可访问类型的名字,那么命名空间或类型名字引用使用给定类型实参构造的类型。u 否则,如果命名空间或类型名字出现的位置,由N的命名空间声明所封闭- 如果命名空间声明包含一个由I 给定名字的using 别名指令,而I带有导入命名空间或类型,并且没有指定参数列表,那么命名空间或类型名字引用该命名空间或者类型- 否则,如果由命名空间声明的using命名空间指示符导入的命名空间,恰好包含带有I 给定名字的,匹配类型参数数量的类型,那么命名空间或类型名字引用由给定类型实参构造的这个类型。- 否则,如果由命名空间声明的using 命名空间指示符导入的命名空间包含多个带有I给定名字的,匹配类型参数数量的类型,那么命名空间或者类型名字是模糊的,并且将导致错误。 - 否则,命名空间或类型名字是未定义的,并且出现编译时错误。
l 否则,命名空间或者类型名字是N.I或者N.I<A1,…,AN>的形式,这里N是一个命名空间或类型名字,I是一个标识符,并且<A1,…,AN>是一个可选类型实参列表。N 被作为命名空间或类型名字而首先决策。如果N的决策失败,将会出现一个编译时错误。否则N.I或者N.I<A1,…,AN>将按如下方式决策。- 如果N引用一个命名空间,并且如果I是内嵌在N中的命名空间名字,并且没有指定类型实参列表,那么命名空间或类型名字引用该内嵌命名空间。- 否则,如果N引用一个命名空间,并且I是在带有匹配类型参数数量的N中的可访问类型的名字,那么命名空间或类型名字引用由给定类型实参构造的那个类型。- 否则,如果N引用类或结构类型,并且I是内嵌在带有与类型参数匹配的N中的可访问类型的名字,那么命名空间或者类型名字引用由给定实参构造的那个类型。- 否则,N.I是一个无效的命名空间名字,并且会出现编译时错误。
对于E.I或E.I<A1,…,AN>形式的成员访问,这里E是一个基本表达式或预定义类型,I是一个标识符,并且<A1,…,AN>是一个可选类型实参列表,将按如下方式被计算和分类。
- 如果I标识一个枚举成员,那么结果是一个值,也就是枚举成员的值。- 否则,E.I是一个无效成员引用,并将导致编译时错误。
- 如果被选择的方法是一个实例方法,与E关联的实例表达式确定委托的目标对象。- 结果是一个D类型的值,也就是引用选择的方法和目标对象的新创建委托。
下面的产生式被使用右移或右移赋值进行了修改。shift-expression:(移位表达式:) additive-expression(附加表达式) shift-expression << additive-expression(移位表达式 << 附加表达式) shift-expression right-shift additive-expression(移位表达式 right-shift 附加表达式)assignment-operator:(赋值运算符:)=+=-=*=/=%=&=|=^=<<=right-shift-assignmentoverloadable-binary-operator:(可重载二元运算符:)+-*/%&|^<<right-shift==!=><>=<= (泛型完)****************************终于把这一章贴完了,哎,手都酸了,有问题的地方希望大家多多提出来,千万别客气:) <script type="text/javascript"><!--google_ad_client = "pub-2947489232296736";/* 728x15, 创建于 08-4-23MSDN */google_ad_slot = "3624277373";google_ad_width = 728;google_ad_height = 15;//--></script><script type="text/javascript"src="http://pagead2.googlesyndication.com/pagead/show_ads.js"></script>
<script type="text/javascript"><!--google_ad_client = "pub-2947489232296736";/* 160x600, 创建于 08-4-23MSDN */google_ad_slot = "4367022601";google_ad_width = 160;google_ad_height = 600;//--></script><script type="text/javascript"src="http://pagead2.googlesyndication.com/pagead/show_ads.js"></script>
接泛型五
20.8表达式和语句
某些表达式和语句的操作针对泛型进行了修改。这一节将介绍这些改变。20.8.1默认值表达式
默认值表达式被用于获得一个类型的默认值(§5.2)。通常一个默认值表达式被用于类型参数,因为如果类型参数的是一个值类型或引用类型,它可能不是已经的。(不存在从null类型到类型参数的转换。)primary-no-array-creation-expression:(基本无数组创建表达式:) … default-value-expression(默认值表达式)default-value-expression:(默认值表达式:) primary-expression . default (基本表达式 .default) predefined-type . default(预定义类型. default)如果一个基本表达式在一个默认值表达式中被使用,并且这个基本表达式不能分为一个类型,那么将会出现一个编译时错误。然而在§7.5.4.1中描述的规则也适用于形成E.default的构件。如果默认值表达式的左边针对一个引用类型在运行时被计算,结果是将null转换到那个类型。如果默认值表达式的左边针对一个值类型在运行时被计算,其结果是值类型的默认值(§4.1.2)。如果类型是一个具有类约束的引用类型或类型参数,默认值表达式是一个常量表达式(§7.15)。此外,如果类型是下列值之一,默认值表达式是一个常量表达式:sbyte、byte、 short、ushort、 int 、 uint 、long 、ulong 、 char 、float 、double 、decimal 或bool。20.8.2对象创建表达式
对象常见表达式的类型可以是一个类型参数。当类型参数被作为对象创建表达式中的类型而指定时,下面两个条件必须具备,否则将会出现编译时错误- 实参列表必须删除
- 必须为类型参数而指定new()形式的构造函数约束
通过创建一个类型参数被绑定到的运行时类型的实例,并调用该类型的默认构造函数,就可以执行对象创建表达式。运行时类型可以是引用或者值类型。
20.8.3运算符的类型
typeof运算符可以用于类型参数。其结果是被绑定到类型参数的运行时类型的System.Type对象。typeof运算符也可以被用于构造类型。class X <T>{ public static void PrintTypes(){Console.WriteLine(typeof(T).FullName);Console.WriteLine(typeof(X<X<T>>).FullName);}}class M{ static void Main(){X<int>.PrintTypes();}}先前的程序将打印如下。System.Int32X<X<Sytem.Int32>>Typeof运算符不能用于没有指定类型实参的泛型类型声明的名字。class X<T>{…}class M{ static void Main(){Type t = typeof(X); //错误,X需要类型实参}}20.8.4引用相等运算符
如果T由一个类约束而约束,引用类型相等运算符可以被用于比较类型参数T的值。引用类型相等运算符的用法可以让类型参数T的实参很容易地与其他为null的实参进行比较,即使T没有类约束也如此。在运行时,如果T是一个值类型,比较的结果将是false。下面的例子检查一个非约束类型参数类型的实参是否是null。class C<T>{ void F(T x){if(x==null) thow new ArgumentNullException();…}} 即使是T可以表示一个值类型,x==null构件也是允许的,并且当T是值类型时,其结果被简单的定义为false。
20.8.5 is运算符
在开放类型上的is运算符操作遵循通常的规则(§7.9.9)。如果e或T的编译时类型是一个开放类型,那么在运行时对于e和T将总是执行动态类型检查。20.8.6as运算符
只要T有一个类约束,类型参数T可被用在as运算符的右边。这种限制是需要的,因为值null可能被作为运算符的结果返回。class X{ public T F<T>(object o) where T:Attribute{return o as T; //ok,T有一个类约束}public T G<T>(object o){return o as T; //错误,T没有约束}}在as运算符(§7.9.10)的当前规范中,对于表达式e as T最后一点表明,如果从e的编译时类型到T,不存在有效的显式引用转换,将会出现编译时错误。对于泛型,这条规则稍微作了修改。如果E的编译时类型或T是一个开放类型,在这种情况下将不会出现编译时错误;相反,运行时检查将会执行。20.8.7异常语句
对于开放类型,throw(§8.9.5)和try(§8.10)的通常规则是适用的。- 只要类型参数具有System.Exeption异常(或子类具有)作为类约束,那么throw语句可以被用作其类型有一个类型参数给定的表达式。
- 只要类型参数System.Exception(或子类子类具有)作为类约束,那么在catch语句中的命名的类型可能是一个类型参数。
20.8.8 lock语句
lock语句可以被用作其类型由一个类型参数给定的表达式。如果表达式的运行时类型是一个值类型,lock将没有效果(因为对于装箱值不能有任何其他的引用)。20.8.9 using 语句
using 语句(§8.13)遵循通常的规则:表达式必须被隐式的转换到System.IDisposable。如果类型参数通过System.IDisposable而约束,那么该类型的表达式可以使用using 语句。20.8.10 foreach语句
给定如下形式的foreach语句foreach(ElementType element in collection) statement如果集合表达式是一个没有实现集合模式的类型,但为每个类型T实现了构造接口System.Collections.Generic.IEnumerable<T>,那么foreach语句的扩展是IEnumerator<T> enumerator = ((IEnuemrable<T>)(collection).GetEnumerator();try{ where (enumerator.MoveNext()){ElementType element = (ElementType)enumerator.Current; statement;}}finally{enumerator.Dispose();}20.9查找规则修订
泛型修改了用于查找和绑定名字的某些基本规则。下面几节在考虑泛型的情况下,重新叙述了所有的基本名字查找规则。20.9.1命名空间和类型名字
如下内容可替换§3.8。在C#程序中有几个上下文需要指定命名空间或者类型名字。任何形式的名字都可以由一个或多个由“.”标记分隔的标识符号组成。namespace-name:(命名空间名字:) namespace-or-type-name(命名空间或类型名字)type-name:(类型名字:) namespace-or-type-name(命名空间或类型名字)namespace-or-type-name:(命名空间或类型名字:) identifier type-argument-list opt(标识符 类型实参列表可选) namespace-or-type-name . identifier type-argument-list opt( 命名空间或类型名字. 标识符 类型实参列表可选)命名空间名字是引用命名空间的命名空间名字或类型名字(namespace-or-type-name)。见下面所描述的决策,命名空间名字的命名空间或类型名字必须引用一个命名空间,否则出现编译时错误。在一个命名空间名字中不能有类型实参(只有类型可以具有类型实参)。类型名字是一个引用类型的命名空间或类型名字(namespace-or-type-name)。见下面所描述的决策,类型名字的命名空间或类型名字必须引用一个类型,否则出现编译时错误。命名空间或类型名字的意义按如下确定。- 如果命名空间或类型名字是I或I<A1,…,AN>的形式,其中I 是一个单一标识符,并且<A1,…,AN>是一个可选类型实参列表。
u 否则,如果I是T中可访问成员的名字,并且如果那个成员是一个带有匹配类型参数数量的类型,那么命名空间或类型名字引用类型T.I或者类型T.I<A1,…AN>。注意当确定命名空间或类型名字的意义时,无类型成员(常数、字段、方法、属性、索引器、运算符、实例构造函数、析构函数和静态构造函数)和带有不同数量的类型参数成员将会被忽略。- 否则,对于在以命名空间或类型名字出现的命名空间开始的每个命名空间N,并继续使用每个封闭命名空间(如果有的话),然后以全局命名空间结束,下面的步骤将会被计算,直到该实体被定位。u 如果I 是在N中的命名空间中的名字,并且没有指定类型实参列表,那么命名空间或类型名字引用该个命名空间。u 否则,如果I是在N中带有匹配类型参数数量的可访问类型的名字,那么命名空间或类型名字引用使用给定类型实参构造的类型。u 否则,如果命名空间或类型名字出现的位置,由N的命名空间声明所封闭- 如果命名空间声明包含一个由I 给定名字的using 别名指令,而I带有导入命名空间或类型,并且没有指定参数列表,那么命名空间或类型名字引用该命名空间或者类型- 否则,如果由命名空间声明的using命名空间指示符导入的命名空间,恰好包含带有I 给定名字的,匹配类型参数数量的类型,那么命名空间或类型名字引用由给定类型实参构造的这个类型。- 否则,如果由命名空间声明的using 命名空间指示符导入的命名空间包含多个带有I给定名字的,匹配类型参数数量的类型,那么命名空间或者类型名字是模糊的,并且将导致错误。 - 否则,命名空间或类型名字是未定义的,并且出现编译时错误。
l 否则,命名空间或者类型名字是N.I或者N.I<A1,…,AN>的形式,这里N是一个命名空间或类型名字,I是一个标识符,并且<A1,…,AN>是一个可选类型实参列表。N 被作为命名空间或类型名字而首先决策。如果N的决策失败,将会出现一个编译时错误。否则N.I或者N.I<A1,…,AN>将按如下方式决策。- 如果N引用一个命名空间,并且如果I是内嵌在N中的命名空间名字,并且没有指定类型实参列表,那么命名空间或类型名字引用该内嵌命名空间。- 否则,如果N引用一个命名空间,并且I是在带有匹配类型参数数量的N中的可访问类型的名字,那么命名空间或类型名字引用由给定类型实参构造的那个类型。- 否则,如果N引用类或结构类型,并且I是内嵌在带有与类型参数匹配的N中的可访问类型的名字,那么命名空间或者类型名字引用由给定实参构造的那个类型。- 否则,N.I是一个无效的命名空间名字,并且会出现编译时错误。
20.9.2成员查找
下面内容可替换§7.3 成员查找是一种根据在上下文中的意义来确定类型的处理过程。在一个表达式中,成员查找可以作为计算一个简单名字或成员访问(§20.9.4)而出现。在类型T中的名字N的成员查找按如下规则确定。- 首先一组名为N的可访问成员被确定。
- 接着,通过其他成员而被隐藏的成员将从这个集合中删除。对于在集合中的每个成员S.M,S是M在其中被声明的类型,下面的规则可适用
- 接着,通过类成员隐藏的接口成员将从该集合中删除。这一步,只有当T是一个类型参数,并且T有类约束和多个接口约束时才有效。对于在集合中的每个成员S.M,其中S是M在其中声明的类型,如果S是一个类声明而不是object的话,下面的规则适用
- 最后,在删除隐藏成员之后,查找的结果将被确定
20.9.3简单名字
如下内容可替换§7.5.2。简单名字由一个标识符,其后可跟随可选的类型参数列表。simple-name:(简单名字:) identifier type-argument-list opt(标识符 类型实参列表可选)对于I或I<A1,…,AN>形式的简单名字,这里I 是一个标识符,I<A1,…,AN>是一个可选类型实参列表,可以被按如下方式计算和分类。- 如果简单名字出现在块内,并且如果块的局部变量声明空间包含由I给定名字的局部变量或参数,那么,这个简单名字引用该局部变量和参数,并且作为一个变量而被分类。如果类型实参列表被指定,将会出现编译时错误。
- 如果简单名字出现在泛型方法声明体之内,并且如果该声明包含由I给定名字的类型参数,那么简单名字引用那个类型参数,如果只定了类型实参列表被,将会出现编译时错误。
- 否则,对于以直接封闭类、结构或枚举声明的实例类型开始的类型T的每个实例,继续采用每个封闭外部类或结构声明的实例类型(如果有的话)。
- 否则,对于带有每个简单名字出现在其中的命名空间的命名空间N,继续采用每个封闭命名空间(如果有的话),并以全局命名空间结束,下面的步骤将被计算,直到一个实体被定位。
20.9.4成员访问
如下内容可代替§7.5.4。成员访问由基本表达式或预定义类型,紧接一个“.”标记,再紧接一个标识符,然后接着可选的类型实参列表而组成。member-access:(成员访问:) primary-expression . identifier type-argument-list opt(基本表达式. 标识符 类型实参列表可选) predefined-type . identifier type-argument-list opt(预定义类型. 标识符 类型实参列表可选)预定义类型:下列之一 bool byte char decimal double float int long object sbyte short string uint ulong ushort对于E.I或E.I<A1,…,AN>形式的成员访问,这里E是一个基本表达式或预定义类型,I是一个标识符,并且<A1,…,AN>是一个可选类型实参列表,将按如下方式被计算和分类。
- 如果E 是一个命名空间,I是E 中嵌套命名空间的名字,并且没有指定类型实参,那么结果就是这个命名空间。
- 如果E是一个命名空间,I是在E中可访问类型的名字,E 匹配类型参数的数量,那么结果就是由给定类型实参构造的类型。
- 如果E是一个预定义类型或作为一个类型而被分类的基本表达式,如果E 不是类型参数,并且如果在E中I的成员查找产生一个匹配,那么E.I被计算,并按如下分类。
- 如果I标识一个枚举成员,那么结果是一个值,也就是枚举成员的值。- 否则,E.I是一个无效成员引用,并将导致编译时错误。
- 如果E是一个属性访问、索引器访问、变量或值,其类型是T,并且在T中I的成员查找产生一个匹配,那么E.I按如下方式被计算和分类。
- 否则,E.I是一个无效成员引用,将导致编译时错误。
20.9.5方法调用
如下内容可替换§7.5.5.1中描述方法调用的编译时处理部分。对于M(A)形式的方法调用的编译时处理,其中M是一个方法组(可能包含一个类型实参列表),A是可选实参列表,由如下步骤组成。- 方法调用的候选集合被构造。对于每个与方法组M关联的方法F
- 候选方法的集合被缩减到只包含从深度派生类型而来的方法:对于在集合中的每个C.F方法,C是F在其中声明的类型,在C的基类型中声明的所有方法都被从集合中删除。
- 如果候选方法的结果集合是空的,那么没有可适用的方法存在,并且会出现编译时错误。如果候选方法并不是在同一类型中声明的,方法调用将是不明确的,并且会出现编译时错误(这后一种情况,只可能出现在对于一个在具有多重直接基接口的接口中的方法的调用,如§13.2.5的描述)。
- 候选方法集合的最佳方法使用重载决策规则(§7.4.2)标识。如果一个单一的最佳方法不能被标识,该方法调用是不明确的,并产生编译时错误。当执行重载决策时,泛型方法的参数在将对应的方法类型参数替换为类型实参(提供的或推断的)之后将被考虑。
- 被选择的最佳方法的最后验证被执行
20.9.6委托创建表达式
如下内容可替换§7.5.10.3中委托创建表达式的编译时处理部分。对于new D(E)形式的委托创建表达式的编译时处理,其中D 是一个委托类型,E是一个表达式,由如下步骤组成。- 如果E是一个方法组
- 如果被选择的方法是一个实例方法,与E关联的实例表达式确定委托的目标对象。- 结果是一个D类型的值,也就是引用选择的方法和目标对象的新创建委托。
- 否则,E是一个委托类型的值
- 否则,委托创建表达式是无效的,并且出现编译时错误。
20.10右移语法改变
泛型使用“<”和“>”字符分隔类型参数和类型实参(与C++的模板语法相似)。构造类型有时可嵌套,如List<Nullable<int>>,但使用这种构件有一些微妙的语法问题:词法将组合这个构件的最后两个标记“>>”(右移运算符),而不是产生句法需要的两个“>”标记。尽管一个可能的解决方案是在两个“>>”中放入空格,这也是很尴尬而令人迷惑的,并没有以任何方式增加程序的简洁性。为了让这些中性的构件维持简单的词法,“>>”和“>>=”标记从词法中删除了,取代的是右移和右移赋值产生式。运算符或标点:之一{ } [ ] ( ) . , : ;+ - * / % & | ^ ! ~= < > ? ++ -- && || == ->!= <= >= += -= *= /= %= &= |=^= << <<=right-shift:(右移:)> >right-shift-assignment:(右移赋值)> >=不像在句法中的其他产生式,在右移和右移赋值产生式的标记之间不允许任何种类的字符存在(甚至是空格)。下面的产生式被使用右移或右移赋值进行了修改。shift-expression:(移位表达式:) additive-expression(附加表达式) shift-expression << additive-expression(移位表达式 << 附加表达式) shift-expression right-shift additive-expression(移位表达式 right-shift 附加表达式)assignment-operator:(赋值运算符:)=+=-=*=/=%=&=|=^=<<=right-shift-assignmentoverloadable-binary-operator:(可重载二元运算符:)+-*/%&|^<<right-shift==!=><>=<= (泛型完)****************************终于把这一章贴完了,哎,手都酸了,有问题的地方希望大家多多提出来,千万别客气:) <script type="text/javascript"><!--google_ad_client = "pub-2947489232296736";/* 728x15, 创建于 08-4-23MSDN */google_ad_slot = "3624277373";google_ad_width = 728;google_ad_height = 15;//--></script><script type="text/javascript"src="http://pagead2.googlesyndication.com/pagead/show_ads.js"></script>
<script type="text/javascript"><!--google_ad_client = "pub-2947489232296736";/* 160x600, 创建于 08-4-23MSDN */google_ad_slot = "4367022601";google_ad_width = 160;google_ad_height = 600;//--></script><script type="text/javascript"src="http://pagead2.googlesyndication.com/pagead/show_ads.js"></script>
- C# 2.0 Specification(泛型六)
- C# 2.0 Specification(泛型六)
- C# 2.0 Specification(泛型六)
- C# 2.0 Specification(二)
- C# 2.0 Specification (四)
- C#2.0 Specification(泛型一)
- C#2.0 Specification(泛型二)
- C# 2.0 Specification (泛型三)
- C# 2.0 Specification (泛型四)
- C# 2.0 Specification(泛型五)
- C# Version 2.0 Specification
- C# 2.0 Specification (泛型三)
- C# 2.0 Specification (泛型四)
- C# 2.0 Specification(泛型五)
- C# 2.0 Specification(二)
- C# 2.0 Specification (四)
- C# 2.0 Specification(二)
- C# 2.0 Specification(泛型五)
- 用 (*it).m 还是 it->m
- 通过避免下列 10 个常见 ASP.NET 缺陷使网站平稳运行
- C# 2.0 Specification(泛型五)
- [转载]ASP.NET AJAX入门系列
- 串口发送数据类
- C# 2.0 Specification(泛型六)
- 串口发送数据类
- 不用第归算法快速显示树,对于Oracle数据库(2)
- 简介使用ASP.NET访问Oracle数据库的方法
- ASP.NET Whidbey 中新的代码编译功能
- 使用更精简的代码保证 ASP.NET 应用程序的安全
- 看看这段代码就知道char到底能不能放下中文字
- Websharp使用说明(1)
- Websharp使用说明(3)