C#中的委托,匿名方法、泛型委托和Lambda表达式表达式演变过程

时间:2022-01-04 19:25:50
 

我为了更好的理解C#中的委托,、泛型委托、匿名方法和Lambda表达式,我把它们的演变过程通过自己的理写了出来,各位高手要是看到有什么不妥的地方,还望指出。

首先,我从一个C语言中很简单的一个问题开始,比较两个数的大小,并将最大的数以string 型输出

首先来看比较常规的写法:

public delegate string DelegateCompare(int Num1,int Num2);  //定义委托

    class Compare

    {

        public static string NumCompare(int Num1, int Num2)

        {

            return Num1 > Num2 ? Num1.ToString() : Num2.ToString();

        }

    }

    class CompareApplication

    {

        static void Main()  

        {

            DelegateCompare delegate1 = new DelegateCompare(Compare.NumCompare);

            string STR = "最大的数位:" + delegate1(10, 20);

            Console.WriteLine(STR);

            Console.ReadLine();

        }

    }

为了精简代码(当然这个理由似乎不够充分),我们决定使用匿名方法,也许这里你并不能看到匿名方法的真正好处,但是,当把.NET方法做为委托参数时或处理时间时,就能看到匿名方法的真正用处。下面是贴过来的代码:

public delegate string DelegateCompare(int Num1,int Num2);  //定义委托

    class CompareApplication

    {

        static void Main()  

        {

            DelegateCompare delegate1 = new DelegateCompare(delegate(int Num1, int Num2) { 

                return Num1 > Num2 ? Num1.ToString() : Num2.ToString(); 

            });

            string STR = "最大的数位:" + delegate1(10, 20);

            Console.WriteLine(STR);

            Console.ReadLine();

        }

    }

正如你所见到的一样,我把Compare类完全删除了,那比较大小的功能是通过什么完成的了,这就是匿名方法,通过delegate关键字,我们声明了一个没有方法名的方法体。

接下来我有个大胆的想法,将委托声明也去掉,这时就应该用到泛型委托

class CompareApplication

    {

        static void Main()  

        {

            Func<int, int, string> delegate1 = new Func<int, int, string>(delegate(int Num1, int Num2)

            { 

                return Num1 > Num2 ? Num1.ToString() : Num2.ToString(); 

            });

            string STR = "最大的数位:" + delegate1(10, 20);

            Console.WriteLine(STR);

            Console.ReadLine();

        }

    }

在上面的代码中,我将委托的声明全部用Func<int, int, string>替代掉了,我先分析一下该表达式如何得来,先看我们的委托是如何定义的:

public delegate string DelegateCompare(int Num1,int Num2),从委托的声明中我们得知,绑定到该委托的方法必须具有两个int型参数并且其返回值类型为string,那么泛型委托Func<int, int, string>的得来就一目了然了。

这时,所有的代码都集中在一个函数里了,够精简了,还能不能更加精简了,好,这时候lambda表达式出场了

class CompareApplication

    {

        static void Main()  

        {

           Func<int, int, string> delegate1 = (x, y) => x > y ? x.ToString() : y.ToString();          

            string STR = "最大的数位:" + delegate1(10, 20);

            Console.WriteLine(STR);

            Console.ReadLine();

        }

    }

我们一定能看出来,这里面最重要的就是这句:Func<int, int, string> delegate1 = (x, y) => x > y ? x.ToString() : y.ToString()。我想我有必要把这句话完整的解释一遍,首先我想知道这句话干了点啥事,它做的事还真不少,定义委托、方法绑定、方法定义,这三件事一气呵成。首先来看委托的定义:Func<int, int, string> delegate1,这段代码告诉我们,我们定义了一个可以绑定具有两个int型参数并且其返回类型为string型的方法的委托,接下来看等号右边,这里就是一个lambda表达式,lambda表达式可以看作是一个匿名方法,以“=>”运算符为标志,“=>”左边部分为传入,该匿名方法的两个参数,注意,这两个参数我们没有声明类型,但编译器会根据前面泛型委托的定义自动推断出其参数类型(返回值类型是同样的原理)。“=>”右边为返回值。

好了,上面就是我对这些概念的理解。本人是个初学者,还请各位高手多多指教。

补充几点:

只有在 Lambda 有一个输入参数时,括号才是可选的;否则括号是必需的。 两个或更多输入参数由括在括号中的逗号分隔

有时,编译器难于或无法推断输入类型。 如果出现这种情况,您可以按以下示例中所示方式显式指定类型:(int x, string s) => s.Length > x

使用空括号指定零个输入参数:() => SomeMethod()

Lambda 语句与 Lambda 表达式类似,只是语句括在大括号中:

(input parameters) => {statement;}

Lambda 语句的主体可以包含任意数量的语句;但是,实际上通常不会多于两个或三个语句。

delegate void TestDelegate(string s);

TestDelegate myDel = n => { string s = n + " " + "World"; Console.WriteLine(s); };
myDel("Hello");

在编写 Lambda 时,通常不必为输入参数指定类型,因为编译器可以根据 Lambda 主体、基础委托类型以及 C# 语言规范中描述的其他因素推断类型。

Lambda 的一般规则如下:

  • Lambda 包含的参数数量必须与委托类型包含的参数数量相同。

  • Lambda 中的每个输入参数必须都能够隐式转换为其对应的委托参数。

  • Lambda 的返回值(如果有)必须能够隐式转换为委托的返回类型。

请注意,Lambda 表达式本身没有类型,因为常规类型系统没有“Lambda 表达式”这一内部概念。但是,有时会不正式地论及 Lambda 表达式的“类型”。 在这些情况下,类型是指委托类型或 Lambda 表达式所转换为的 Expression 类型。