鸿 网 互 联 www.68idc.cn

当前位置 : 服务器租用 > .net技术 > WinRT/Metro > >

C#委托使用匿名方法(一)

来源:互联网 作者:佚名 时间:2012-11-15 10:39
最近看到一本书写到关于匿名方法的使用,写的比较深刻,今天在这里总结一下。由于第一次写博客,如果有不妥的地方,请大家见谅,下面我们转入正题: 1.委托 使用委托工作有两种方式:一种是事先定义好一个方法,然后委托到该方法上,另外一种就是直接在代码

  最近看到一本书写到关于匿名方法使用,写的比较深刻,今天在这里总结一下。由于第一次写博客,如果有不妥的地方,请大家见谅,下面我们转入正题:

  1.委托

  使用委托工作有两种方式:一种是事先定义好一个方法,然后委托到该方法上,另外一种就是直接在代码中使用匿名方法。

  直接使用委托:

Print(string printStr); static void Main(string[] args) { Print print = DelegateMethod; print(); Console.Read(); } DelegateMethod(string printStr) { Console.WriteLine(printStr); }

  使用匿名方法:

  static void Main(string[] args) {   Print print = delegate(string printStr) { Console.WriteLine(printStr + ); }; print(); Console.Read(); }

  在使用匿名方法时候,要注意不能使用跳转语句跳转到该匿名方法的外部,同样不能用跳转语句从外部跳转到匿名方法内部,匿名方法中不能访问不安全代码(unsafe),也 不能访问在匿名方法外部使用的ref和out参数。

  2.匿名方法

  匿名方法在上面已经进行了简单的使用,但是在实际问题中可能遇到的问题要比上面的代码复杂得多,在匿名方法中捕获变量就是难点之一。

  一个简单的例子(我们将上面的代码进行简单的改变):

Print(); static void Main(string[] args) { ; ; Print print = delegate() { Console.WriteLine(temp + localStr + ); }; print(); Console.Read(); }

 

  和你预期的相同,控制台会显示“this is the first DelegateFunction!”。然而我们进行一下改变:

Print(); static void Main(string[] args) { ; ; Print print = delegate() { Console.WriteLine(temp + localStr + ); localStr = ; }; localStr = ; print();//打印出 this is the third DelegateFunction! print();//打印出 this is the second DelegateFunction! Console.Read(); }

  我们来分析一下结果:首先temp作为匿名方法外部变量,在匿名方法中没有对它进行操作,localStr 在匿名方法中我们捕获它并赋值为“the second” ,然而从结果分析来 看这个赋值的操作显然是在打印出this is the third DelegateFunction!之后进行的,然后第二次调用匿名方法时候,才将this is the second DelegateFunction结果打印出来。上面的操作告诉我们,只有在调用匿名方法委托实例的时候才会执行匿名方法内部的操作。单纯的创建委托实例并不会立即执行匿名方法代码块。

   3.匿名方法捕获的变量会延长变量的生存周期

    对于被捕获的变量(localStr)只要有委托实例在引用它,它就会一直存在。

     static void Main(string[] args) { MethodInvoker newDelegate = CreateDelegate(); newDelegate();//第二次输出This  tempCount is 5 Console.Read(); }     static MethodInvoker CreateDelegate() { int tempCount; MethodInvoker method = delegate { tempCount = 5; Console.WriteLine( tempCount++; }; method();//第一次输出This  tempCount is 5 return method; }

  上面的代码输出的结果是两行:This  tempCount is  5。在第二次调用的时候可以看到,正常来说tempCount是CreateDelegate()的局部变量,是在栈上的,在CreateDelegate()方法结束后tempCount会随着一起在栈中被销毁,然而在第二次调用匿名方法的时候tempCount的值会依然存在。秘密在于tempCount并不在栈上,事实上编译器创建了一个额外的类来存储变量,CreateDelegate()方法对该类有一个实例引用,所以它可以使用tempCount,而委托也对该实例有一个引用,除非委托准备好被GC回收,否则那个实例是不会被回收的,香港虚拟主机,这样 出现上面的结果也就是正常的。

  4.局部变量的“实例化”

  我们对上面的代码进行简单的更改:

  MethodInvoker newDelegate = CreateDelegate(); newDelegate();//This tempCount is 5 ;This tempOtherCount is 6 newDelegate();////This tempCount is 5 ;This tempOtherCount is 7 Console.Read();      static MethodInvoker CreateDelegate() { int tempOtherCount = 5; MethodInvoker method = delegate { int tempCount = 5; Console.WriteLine(, tempCount); Console.WriteLine(, tempOtherCount); tempCount++; tempOtherCount++; }; method(); method; }

  从上面的输出结果可以看出委托在捕捉变量的时候,要注意变量的位置,tempCount 和 我们在外部调用了两次委托实例,那相当于生成了两个不一样的tempCount实例,而tempOtherCount则是相同的一个实例,不同委托调用时,每个委托的tempCount实例是有区别的,而他们对tempOtherCount共用一个引用实例。在使用匿名方法的时候自己的小小疏忽可能会导致意想不到的结果。

  以上是对匿名方法捕捉变量的简单举例,在实际问题中,使用捕获变量这种方法可以简化代码。以下是捕获变量的规则:

  如果不用捕获变量的方法代码同样简单,就不用。

  在循环体中要注意你是用的委托是否需要在循环迭代结束以后延续,香港服务器租用,以及是否想让它继续使用那个被捕捉变量的后续值,否则的话,就在循环内另外建一个变量来复制你想要   的值。

  多委托时候要考虑是否这些委托要捕捉同一个变量。

  如果被捕捉的变量不会发生改变,就不需要这么多的担心。

  从垃圾回收的角度讲,思考任何捕获变量的被延长的生存期。这方面问题一般都不大,但是假如捕获的对象会产生昂贵的内存开销,美国服务器,这方面问题会凸现出来。(这点很重要)

 

 

  

网友评论
<