委托:就是一个类,通过IL中间语言编译器可以看到,就是一个class 的定义,无论它后面怎么变化,是 Delegate 自定义还是用内置委托 Action Func 都是 一个类,
匿名方法:委托可以调用具体方法名作为参数,也可以直接在里面写方法体,这个方法体就是匿名方法,
匿名方法,直白点说,就是没有方法体的方法。
lambda表达式 就是一个方法,表面看是一个匿名方法,在IL里面你可以看到,他跟匿名方法又不一样,他会定义为一个普通方法。
都说C#是C语言版的Java,它是基于Java的基础上,增加的更多的独有的语言功能,而委托就是其中之一,而也就是委托让我感觉到从Java转到C#的一个大难点。
委托是通过delegate关键字来定义,简单来说,委托是一个类,它定义了方法的类型,使得可以将方法当作另一个方法的参数来进行传递。这方面就有些相似于JavaScript的函数,它也是能够将函数作为参数进行传递。至于为什么要这么做,其原理是观察者设计模式,这里我不做详细说明。
进入正题,首先我先给出这三者之间的从属关系:委托->匿名表达式->Lambda表达式。
从关系式不难看出,Lambda表达式一定能够转化成匿名表达式和原始的委托方式,而匿名表达式也一定能够转换成原始的委托方式。
上代码:
/ //定义委托类型
delegate int calculator(int x, int y);
static void Main(string[] args)
{
//初始化委托类型(命名方法),注意是add不是add()
calculator add1 = new calculator(add);
//匿名方法是通过使用 delegate 关键字创建委托实例来声明的
calculator add2 = delegate (int a, int b)
{
return a + b;
};
//任何 Lambda 表达式都可以转换为委托类型
//表达式 lambda
calculator add3 = (a, b) => a + b;
//Func 类型:有任意返回值的委托类型,最后一个泛型是返回值类型
Func<int, int, int> add4 = (a, b) => a + b;
//给委托变量再绑定或者删除一个方法
add1 += sub;
//add1 -= sub;
//add1()只会输出最近的那个函数的结果
Console.WriteLine(add1(1, 6));
Console.WriteLine(add2(2, 6));
Console.WriteLine(add3(3, 6));
Console.WriteLine(add4(4, 6));
}
private static int sub(int a, int b)
{
return 4 * a - b;
}private static int add(int a, int b)
{
return 2 * a + b;
}
上述代码用4种方式实现一个加法功能:
第一种方式是最原始的委托使用方式,定义,声明,初始化,调用。
第二种方式是匿名方法的形式,通过delegate关键字将所需要绑定的方法直接内部实现。
第三种方式是 Lambda 表达式,进一步简化第二种方式的代码,变得更加简洁美观。
第四种方式是调用 .NET Core 框架内部已有的委托类型,此方式实现可重用。(推荐的使用方式)
由于委托的参数是方法,所以也可以将多个方法赋给同一个委托,当调用这个委托的时候,将依次调用其所绑定的方法。
在 .NET Core 框架内部定义的常用委托类型有两种:Action 类型与Func 类型。
它俩都是泛型类型,只不过前者是具有 void 返回类型的委托类型,而后者是有任意返回值的委托类型。
在C#中Lambda 表达式具体来说也有多种类型,上述代码的Lambda 表达式属于表达式 lambda,基础常用的还有语句Lambda和含标准查询运算符的 lambda。
上代码:
int[] numbers = { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 };
//匿名方法
int oddNumbers1 = numbers.Count(delegate (int n)
{
return n % 2 == 0;
});
Console.WriteLine(oddNumbers1);
//含标准查询运算符的 lambda
int oddNumbers2 = numbers.Count(n => n % 2 == 1);
Console.WriteLine(oddNumbers2);
//Action 类型:具有 void 返回类型的委托类型
//匿名方法
Action<int[], int, int> change1 = delegate (int[] nums, int a, int b)
{
var tmp = nums[a];
nums[a] = nums[b];
nums[b] = tmp;
};
//语句Lambda
Action<int[], int, int> change2 = (nums, a, b) =>
{
var tmp = nums[a];
nums[a] = nums[b];
nums[b] = tmp;
};
change1(numbers, 0, 1);
change2(numbers, 2, 3);
foreach (var item in numbers)
{
Console.Write(item + " ");
}
相信经过上述两个案例的对比代码,这三者之间的关系应该就很容易理解了。
其实刚开始就想直接写出Lambda的确挺难的,还是先从委托开始慢慢过渡到熟悉匿名函数,最后就能轻易的掌握Lambda表达式!