C#2.0新增功能03 匿名方法

  • 2019 年 10 月 4 日
  • 笔记

  在 2.0 之前的 C# 版本中,声明委托的唯一方式是使用命名方法。 C# 2.0 引入匿名方法,在 C# 3.0 及更高版本中,Lambda 表达式取代匿名方法作为编写内联代码的首选方式。 但是,本主题中有关匿名方法的信息也适用于 Lambda 表达式。 在有一种情况下,匿名方法提供 Lambda 表达式中没有的功能。 使用匿名方法可省略参数列表。 这意味着匿名方法可转换为具有多种签名的委托。 Lambda 表达式无法实现这一点。 有关 Lambda 表达式的详细信息,请参阅 Lambda 表达式

创建匿名方法实际上是一种将代码块作为委托参数传递的方式。 这里是两个示例:

// 为单击事件创建处理程序  button1.Click += delegate(System.Object o, System.EventArgs e)                   { System.Windows.Forms.MessageBox.Show("Click!"); };
// 创建一个委托.  delegate void Del(int x);    // 使用匿名方法实例化委托  Del d = delegate(int k) { /* ... */ };

由于使用匿名方法无需创建单独的方法,因此可减少对委托进行实例化的编码开销。

例如,在因不得不创建方法而可能出现非必要开销的情况下,指定代码块(而不是委托)很有用处。 开始新线程就是一个很好的示例。 此类创建一个线程,且还包含该线程执行的代码,而无需为委托创建其他方法。

void StartThread()  {      System.Threading.Thread t1 = new System.Threading.Thread        (delegate()              {                  System.Console.Write("Hello, ");                  System.Console.WriteLine("World!");              });      t1.Start();  }

备注

匿名方法的参数范围为匿名方法块。

如果目标在匿名方法块之外,匿名方法块内具有 gotobreakcontinue 等跳转语句是一种错误。 如果目标在匿名方法块之内,匿名方法块外具有 gotobreakcontinue 等跳转语句也是一种错误。

范围包含匿名方法声明的本地变量和参数称为此匿名方法的外部变量。 例如,在如下代码段中,n 是一个外部变量:

int n = 0;  Del d = delegate() { System.Console.WriteLine("Copy #:{0}", ++n); };

创建委托时,对外部变量 n 的引用被视为已捕获。 不同于本地变量,已捕获的变量的生存期一直延伸至引用匿名方法的委托具有垃圾回收资格为止。

匿名方法无法访问外部范围的 inrefout 参数。

无法在匿名方法块内访问任何不安全代码。

不允许在 is 运算符左侧使用匿名方法。

示例

如下示例演示实例化委托的两种方式:

  • 将委托与匿名方法相关联。
  • 将委托与命名方法 (DoWork) 相关联。

在每一种情况下,调用委托时均显示一条消息。

// 定义委托.  delegate void Printer(string s);    class TestClass  {      static void Main()      {          // 使用匿名方法实例化委托类型          Printer p = delegate(string j)          {              System.Console.WriteLine(j);          };            // 匿名委托调用的结果          p("The delegate using the anonymous method is called.");            // 使用命名方法“DoWork”的委托实例化          p = DoWork;            // 传统方式委托调用的结果          p("The delegate using the named method is called.");      }        // 与命名委托关联的方法。      static void DoWork(string k)      {          System.Console.WriteLine(k);      }  }  /* 输出:      The delegate using the anonymous method is called.      The delegate using the named method is called.  */