part01.03 委托与 Lambda 表达式(二):匿名方法

匿名方法

在 2.0 之前的 C# 版本中,声明委托的唯一方法是使用命名方法。 C# 2.0 引入了匿名方法,而在 C# 3.0 及更高版本中,Lambda 表达式取代了匿名方法,作为编写内联代码的首选方式。 不过,本主题中有关匿名方法的信息同样也适用于 Lambda 表达式。 有一种情况下,匿名方法提供了 Lambda 表达式中所没有的功能。 就是可使用匿名方法来忽略参数列表。 这意味着匿名方法可转换为具有各种签名的委托。 这对于 Lambda 表达式来说是不可能的。

匿名方法的简要说明:

1.“匿名方法” 就是没有名称的方法,通常用于将代码块作为委托参数进行传递。

2.匿名函数是一个 “内联(inline)” 语句或表达式,可在需要委托类型的任何地方使用。

3.匿名函数可以使用匿名方法来初始化命名委托,或传递命名委托(而不是命名委托类型)作为方法参数。

使用匿名方法处理委托和使用 Lambda 表达式处理委托实例:相关代码说明

 1  /// <summary>
 2     /// 定义一个委托方法(类型)
 3     /// </summary>
 4     /// <param name="i">int 变量</param>
 5     /// <param name="j">double 变量</param>
 6     delegate void DelegateMethod(int i, double j);
 7 
 8     /// <summary>
 9     /// 定义一个普通的类
10     /// </summary>
11     class SomeClass
12     {
13         /// <summary>
14         /// 定义一个打印两个数字的方法
15         /// </summary>
16         /// <param name="m"></param>
17         /// <param name="n"></param>
18         public void PrintDigit(int m, double n)
19         {
20             Console.Write(m * n + " ");
21         }
22     }
23 
24     class Program
25     {
26         static void Main(string[] args)
27         {
28             #region 实例化委托的传统方式
29             var a = new SomeClass();
30 
31             // 使用 SomeClass 的实例方法实例化委托
32             var b = new DelegateMethod(a.PrintDigit);
33             // 此时委托实例执行的是:a.PrintDigit
34             b(1, 2.5);
35             #endregion
36 
37             #region 使用匿名方法处理委托
38             DelegateMethod c = delegate (int m, double n) 
39             {
40                 Console.Write(m + n + " ");
41             };
42             c(1, 2.5);
43             #endregion
44 
45             #region 使用 Lambda 表达式处理委托实例化
46             DelegateMethod d = (int m, double n) => { Console.Write(m - n + " "); };
47             d(1, 2.5);
48             #endregion
49 
50             Console.ReadKey();
51         }
52     }
View Code

Func<> 和 Action<> 简介

public delegate TResult Func<in T, out TRsult>(T arg)

1. 类型参数:

  In T : 此委托封装的方法的参数类型。该类型参数是可逆的,即可以使用指定的类型或派生程度更低的类型。

  out TRsult : 此委托封装的方法的返回值类型。该类型参数是协变的,即可以使用指定的类型或派生类更高的类型。

2.参数 arg 类型

  T : 此委托封装的方法的参数。

3.返回值类型

  Tresult : 此委托封装的方法的返回值

可以使用此委托表示一种能以参数形式传递的方法,而不是显式声明自定义委托。封装的方法必须与此委托定义的方法签名相对应。也就是说,封装的方法必须具有一个通过值传递给它的参数,并且必须返回值。

若要引用具有一个参数并返回 void 的方法,请改用 Action<T> 委托。

            //  带返回值的委托,实例化 Func<T1,T2,Tresult> 委托,不需要显式定义一个新委托并将命名方法分配给该委托
            Func<int, double, double> a = (m, n) => { return m * n; };
            Console.WriteLine(a);
            Console.WriteLine(a(10, 25.2));

            //  不带返回值的委托
            Action<int> b = x => { Console.WriteLine(x); };
            b(100);
           
            Console.ReadKey();                           

 要将代码块传递为委托参数,创建匿名方法则是唯一的方法。通过使用匿名方法,由于不必创建单独的方法,因此减少了实例化委托所需的编码系统开销。

// 为点击事件创建一个处理程序。
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();
}

匿名方法的参数的范围是 “匿名方法块” 。

如果局部变量和参数的范围包含匿名方法声明,则该局部变量和参数称为该匿名方法的 “外部” 变量。

//    n 是一个外部变量
int n = 0;
Del d = delegate() { System.Console.WriteLine("Copy #:{0}", ++n); };

外部变量的引用  被认为是捕获在创建委托时。 与本地变量不同,捕获的变量的生存期内扩展,直到引用该匿名方法委托被垃圾回收。

匿名方法不能访问外部范围的 ref  或 out 参数。

在 “匿名方法块” 中不能访问任何不安全代码。

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

实例化委托的两种方法:

  • 使委托与匿名方法关联。

  • 使委托与命名方法 (DoWork) 关联。

// 声明一个委托
    delegate void Printer(string s);

    class TestClass
    {
        static void Main()
        {
            // 使用匿名方法实例化委托类型
            Printer p = delegate (string j)
            {
                System.Console.WriteLine(j);
            };

            // 匿名委托调用的结果
            p("调用使用匿名方法的委托");

            // 委托实例化使用命名方法“DoWork”
            p = new Printer(TestClass.DoWork);

            // 传统委托调用的结果
            p("调用使用命名方法的委托");
        }

        // 与命名委托关联的方法
        static void DoWork(string k)
        {
            System.Console.WriteLine(k);
        }
    }
    /* 输出:
         调用使用匿名方法的代理。
         调用使用命名方法的委托。
    */
原文地址:https://www.cnblogs.com/huangzewei/p/7285210.html