日期:2013-01-22  浏览次数:20651 次

21匿名方法
21.1.匿名方法表达式
匿名方法表达式(anonymous-method-expression)定义了匿名方法(anonymous method),它将计算为引用该方法的一个具体值。

l primary-no-array-creation-expression(基本非数组创建表达式:)

anonymous-method-expression(匿名方法表达式)

l anonymous-method-expression:
delegate anonymous-method-signature opt block(匿名方法表达式: delegate 匿名方法签名 可选 块)

l anonymous-method-signature:
( anonymous-method-parameter-list opt )(匿名方法签名: 匿名方法参数列表 可选)

l anonymous-method-parameter-list:
anonymous-method-parameter
anonymous-method-parameter-list , anonymous-method-parameter(匿名方法参数列表: 匿名方法参数 匿名方法参数列表)

l anonymous-method-parameter:
parameter-modifieropt type identifier(匿名方法参数: 参数修饰符 可选 类型 标识符)

匿名方法表达式被归类为具有特定转换规则(§21.3)的值。

匿名方法表达式为参数、局部变量和常数定义了一个新的声明空间,并且为标签(§3.3)定义了一个新的声明空间。



21.2匿名方法签名
可选的匿名方法签名(anonymous-method-signature)为该匿名方法定义了正式参数的名字和类型。匿名方法的参数作用域为块(block)。匹配其作用域包含匿名方法表达式(anonymous-method-expression)的局部变量、局部常数或参数的名字,对于匿名方法参数的名字来说是一个编译时错误。

如果一个匿名方法表达式具有匿名方法签名,那么与之兼容的委托类型将被限制为那些具有相同顺序(§21.3)相同参数类型和修饰符的委托类型集合。如果匿名方法表达式不具有匿名方法签名,那么与之兼容的委托类型将被限制为那些没有输出参数的委托类型集合。



请注意,匿名方法签名不能包含特性或者参数数组。不过,匿名方法签名可以与其参数列表包含参数数组的委托类型兼容。



21.3匿名方法转换
匿名方法表达式被归类为一个无类型的值。匿名方法表达式可以用于委托创建表达式(§21.3.1)中。匿名方法表达式的所有其他合法的使用取决于在此定义的隐式转换。

隐式转换存在来自于与任何委托兼容的匿名方法表达式。如果D是一个委托类型,而A是一个匿名方法表达式,那么如果下面的条件满足的话,D就与A兼容:

l 首先,D的参数类型与A兼容:

n 如果A不包含匿名方法签名,那么D可以有零或多个任意类型的参数,前提是D没有任何参数具有输出参数修饰符。

n 如果A具有匿名方法签名,那么D必须具有相同数量的参数,A的每个参数与D的对应参数必须具有相同的类型,并且在A上的每个参数的ref或out修饰符的存在与否,都必须与D的对应参数相匹配。D的最后一个参数是否是参数数组和D与A的兼容性无关。

l 其次,D的返回类型必须与A兼容,对于这些规则,不考虑A包含任何其他匿名方法块的情况。

n 如果D采用void声明返回类型,那么包含在A中的任何返回语句都不应该指定表达式。

n 如果D采用类型R声明返回类型,那么那么包含在A中的任何返回语句的都必须指定一个可以隐式转换(§6.1)到R的表达式。并且,A的块的结束点必须是不可达的。

除了到与之兼容的委托类型的任何隐式转换之外,不存在匿名方法的任何其他转换,即便是对于object类型也是如此。

下面的例子说明了这些规则:

delegate void D(int x);

D d1 = delegate { }; // Ok
D d2 = delegate() { }; // 错误,签名不匹配
D d3 = delegate(long x) { }; //错误,签名不匹配
D d4 = delegate(int x) { }; // Ok
D d5 = delegate(int x) { return; }; // Ok
D d6 = delegate(int x) { return x; }; // 错误,返回类型不匹配

delegate void E(out int x);

E e1 = delegate { }; // 错误e具有输出参数
E e2 = delegate(out int x) { x = 1; }; // Ok
E e3 = delegate(ref int x) { x = 1; }; //错误,签名不匹配

delegate int P(params int[] a);

P p1 = delegate { }; // 错误,块的结束点可达

P p2 = delegate { return; }; // 错误,返回类型不匹配

P p3 = delegate { return 1; }; // Ok
P p4 = delegate { return "Hello"; }; //错误,返回类型不匹配
P p5 = delegate(int[] a) { // Ok
return a[0];
};
P p6 = delegate(params int[] a) { // 错误, 具有params 修饰符
return a[0];
};
P p7 = delegate(int[] a) { //错误,返回类型不匹配
if (a.Length > 0) return a[0];
return "Hello";
};

delegate object Q(params int[] a);

Q q1 = delegate(int[] a) { // Ok
if (a.Length > 0) return a[0];
return "Hello";
};

21.3.1委托创建表达式
委托创建表达式[delegate-creation-expression (§7.5.10.3)]可被用作将匿名方法转换到一个委托类型的替代语法。如果用作委托创建表达式的实参的表达式是一个匿名方法表达式,那么匿名方法将使用上面定义的隐式转换规则转换到给定的委托类型。例如,如果D是一个委托类型,那么表达式

new D(delegate { Console.WriteLine("hello"); })

等价于

(D) delegate { Console.WriteLine("hello"); }



21.4匿名方法块
匿名方法表达式的块遵循下列规则:

l 如果匿名方法包含签名,那么在签名中指定的参数在块内是有效的。如果匿名方法不具有签名,它可以被转换为具有参数的委托类型(§21.3),但参数在块内不可访问。

l 除了在最接近的封闭匿名方法签名中指定的ref和out参数(如果有的话)以外,对于块来说访问ref或者out参数将导致编译时错误。

l 当t