zoukankan      html  css  js  c++  java
  • 3.C#2.0之匿名方法(完成)

      3.1匿名方法表达式

         匿名方法表达式是具有特定转换规则的值,它定义了匿名方法,并得到引用该方法的一个具体值,这个值没有类型,但它可以被隐式转换到与之兼容的委托类型;匿名方法表达式为参数、局部变量、常数定义了一个新的声明空间,并且为标签定义了一个新的声明空间。

      3.2匿名方法签名

         可选的匿名方法签名,为该匿名方法定义了正式参数的名称和类型,参数的作用域就是匿名方法的块;如果参数的名称,与作用域包含这个匿名方法表达式的局部变量、局部常量或参数的名称匹配,那么会产生一个编译时错误。

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

         注:匿名方法签名不能包含特性或参数数组;但匿名方法签名可以和其参数列表包含参数数组的委托类型兼容。

      3.3匿名方法转化

         匿名方法表达式是一个无类型,可用于委托创建表达式,至于其他所有合法的使用取决于在此定义的隐式转化:匿名方法表达式与任何与之兼容的委托类型之间都存在隐式转化,如果D是一个委托类型,A是一个匿名方法表达式。如果满足下面条件,那么D就与A兼容:

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

                    -如果A不包含匿名方法签名,那么D可以有任意类型的参数,前提是D的参数没有任何out参数修饰符;

                    -如果A具有匿名方签名,那么D必须具有相同数量、类型的参数,且A上的每个参数的ref/out修饰符也必须相对应;D的最后一个参数是否是参数数组,和D与A的兼容性无关;

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

                    -如果D是void,那么包含在A中的任何返回语句都不应该指定表达式;

                    -如果是R类型返回类型,那么包含在A中的任何返回语句都必须指定一个可以隐式转换到R的表达式,且A的块的结束点必须是不可到达的。

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

         委托创建表达式可用做匿名方法转换到一个委托类型的替代语言,如果用做委托创建表达式的实参的表达式是一个匿名方法表达式,那么匿名方法将使用上面定义的隐式转化规则转换到给定的委托类型。如果D是一个委托类型:

      3.4匿名方法块

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

              -如果匿名方法包含标签,那么标签中的参数在块中是有效的;如果没有标签,它可以被转换为具有参数的委托类型,但参数不能访问块内;

              -除了在最接近封闭匿名方法签名中指定ref和out参数以外,对于块来说,访问ref/out参数将导致编译时错误;

              -当this的类型是一个结构类型时,对于块来说,访问this将导致编译时错误。无论访问时显式的还是隐式的都如此。该规则只是禁止此类访问方式,并不影响在结构中成员查找的结果;

              -块可以访问匿名方法的外部变量。当匿名方法表达式被求值的时候,对于外部变量的访问,将会引用活动的变量的实例;

              -对于块来说,包含一个其目标在块之外,或一个内嵌的匿名方法的块之内的goto、break、continue语句,都会导致编译时错误;

              -在块内的return语句,将从最接近的封闭匿名方法调用中返回控制权,而不是从封闭函数成员中返回。在return语句中指定的表达式必须与某个委托类型兼容,而最接近的匿名方法表达式将被转换到该委托类型。

         除了通过匿名方法表达式求值和调和外,执行一个匿名方法的程序块,并没有明确地限制。具体来说,就是编译器可以通过合成一个/多个命名方法/类型来实现匿名方法。任何此类合成的元素的名字,都必须保留在编译器的使用空间中:名字必须保留两个连续下划字符。

      3.5外部变量

         作用域包含匿名方法表达式的任何局部变量、值参数、参数数组,都被称为匿名方法表达式的外部变量。在类的实例函数成员中,this值被认为是一个值参数,它也是包含在函数成员内的任何匿名方法表达式的外部变量。

       3.5.1 捕获外部变量

         当外部变量被匿名方法引用时,就可以说这个外部变量被匿名方法所捕获。通常,局部变量的生存周期被限制为它所关联的程序块/语句的执行去,但被捕获时,外部变量的生存周期至少延长到引用匿名方法的委托可以被垃圾回收时为止。

         在代码中,局部变量就是x,x被捕获后,生存期至少延长到从F中返回的委托可以被垃圾回收为止。匿名方法每次调用都在相同的实例上进行操作,该代码的输出结果为:1 2 3 

         当局部变量/值参数被匿名方法捕获时,该局部变量/值参数将不再被认为是固定变量,而是被认为是可以定变量;因此任何想取得被捕获的外部变量地址的不安全代码都必须首先使用fixed语句固定该变量。

       3.5.2 局部变量实例化

         当程序执行到变量的作用域时,就认为局部变量被实例化了。

         这个代码中,x就被实例化和初始化了三次,每次迭代都有一次;但如果x在循环外面,则x只会实例化一次。

         通常我们无法确切地看到一个局部变量多久被实例化一次,因为实例化的生命期被拆分了,可能的情况是每次实例化都只是使用相同的存储位置。然而当一个匿名方法捕捉一个局部变量时,实例化的影响就很明显了。比如:

         结果是:1 3 5,但如果x声明到循环之外:

         结果就是:5 5 5

         依据相等运算,在F的新版本中创建的三个委托是等价的,并且允许编译器将三次实例化优化为一个单一的委托实例。你可以让匿名方法委托共享某些具有其他单独实例的被捕获变量。

         这三个委托捕获了x的同一实例,但捕获了y的多个单独实例,结果为:1 1     2 1     3 1 

         单独的匿名方法可以捕获外部变量的相同实例。

         这两个匿名方法捕获了局部变量x的同一实例,并且它们可以通过该变量"通信"。该实例输出如下:5 10

      3.6匿名方法求值

         匿名方法表达式的运行时求值产生一个引用匿名方法的委托实例,并且被捕获的外部变量的集合在求值时是活动的;当由匿名方法表达式所产生的委托被调用时,匿名方法就会执行,方法体内的代码将使用由该委托引用而被捕获的外部变量执行。

         由匿名方法表达式产生的委托调用列表包含一个单一入口,该委托的确切目标对象和目标方法都是未指定的。需要特别注意的是,委托的目标对象是否未为null,以及封闭函数成员的this值或其他对象,都是未指定的。

         对于语义上相同的匿名方法表达式的求值,如果它们具有相同被捕后的外部变量集合,可以返回相同的委托实例。语义上相同就是说:该匿名方法的执行期在所有情况下,在给定相同实参时都产生相同的效果。

         由于两个匿名方法委托具有被捕获外部变量的相同集合,并且匿名方法在语义上是相同的,因此允许编译器产生引用同一目标方法的委托;实际上,这里允许编译器从两个匿名方法表达式返回相同的委托实例。

       3.7委托实例相等性

         如下规则适用由匿名方法委托实例的相等运算符和object.Equals方法产生的结果:当委托实例是由具有相同被捕获外部变量集合的语义相同的匿名方法表达式求值而产生时,它们可以相等,但没必要;如果语义不同的匿名方法表达式产生,或被捕获的外部变量集合不同时,则绝不相等。

      3.8明确赋值

         匿名方法参数的明确赋值状态与命名方法是相同的。也就是引用参数和值参数被明确地赋初值,而输出参数不用赋初值,并且输出参数在匿名方法正确返回之前必须被明确赋值。

         当控制转换到匿名方法表达式的程序快时,对外部变量v的明确赋值状态,与在匿名方法表达式之前的v的明确赋值状态是相同的;而在匿名方法内的外部变量赋值,对匿名方法外的外部变量没有影响。

      3.9方法组转换

         与本章第三节描述的隐式匿名方法转换相似,从方法组到兼容的委托类型也存在隐式转换:对于给定的方法组E和委托类型D,如果允许new D(E)形式的委托创建表达式,那么就存在从E到D的隐式转换,并且转换的结果恰好等价于new D(E)。

         构造函数用new运算符创建了两个委托实例,隐式方法组转换允许将之简化为:

         对于所有其他隐式和显示的转换,转换运算符可以用于显示地执行一个特定转换。

         方法组和匿名方法表达式可以影响重载决策,但它们并不参与类型推断。

  • 相关阅读:
    QT获取句柄
    java多线程关键字volatile、lock、synchronized
    Java几种常见的设计模式
    将博客搬至CSDN
    0228-0308的笔记
    深入理解es6-Promise对象
    彻底理解正则
    es6学习笔记-class之继承
    es6学习笔记-class之一概念
    arguments对象详解
  • 原文地址:https://www.cnblogs.com/dreamoffire/p/10186704.html
Copyright © 2011-2022 走看看