C#学习笔记14:Action委托和Func委托、多播委托、匿名方法、Lambda表达式

-呈阶梯状分布- 10 次阅读 1376 字 发布于 18 天前 最后更新于 17 天前 C#学习笔记


Action委托和Func委托

委托

首先,委托的定义方式如下:

delegate 返回值类型 委托名(参数1, 参数2, 参数n...);

在定义完委托后,我们就可以用委托名实例化一个委托对象:

委托名 变量名 = 方法名;

之后,变量名内存储的就是方法了,这就是委托的基本用法。

Action委托

对于没有返回值的方法,如果我们希望简单地创建其委托对象,可以使用Action委托,实例化Action委托的写法如下:

Action<参数1类型, 参数2类型, 参数n类型...> 变量名 = 方法名;

通过这种简单的写法,我们便能将原先要写更多的委托实例化缩减为一行。

static void Sum(int a, int b)
{
    Console.WriteLine(a+b);
}
// 原先的写法
delegate void DelegateClass(int a, int b);
DelegateClass delegateObject = Sum;
// 现在的写法
Action<int, int> actionDelegate = Sum;

对于没有参数也没有返回值的情况,可以不写Action后的尖括号。

Func委托

对于有返回值的方法,可以使用Func委托,只需要在Action委托中放参数类型的位置的最后一位,填入返回值类型即可。
写法如下:

Func<参数1类型, 参数2类型, 参数n类型..., 返回值类型> 变量名 = 方法名;

其余一切与Action委托相同。

多播委托

基本使用

我们先定义两个方法:

static void Method1()
{
    Console.WriteLine("1");
}
static void Method2()
{
    Console.WriteLine("2");
}

可以看到,两个方法的作用分别是输出1和输出2。
现在,我们为Method1创建委托:

Action action1 = Method1;  // 第一个方法

之后,我们做一个特殊的操作:为action1变量再加上一个方法。

Action action1 = Method1;  // 第一个方法
action1 += Method2;  // 第二个方法

此时,我们若使用action1()执行委托对象,输出结果如下:

1
2

可以看到,action1()先执行了第一个方法Method1,又执行了第二个方法Method2。
我们可以再多加几个方法:

Action action1 = Method1;  // 第一个方法
action1 += Method2;  // 第二个方法
action1 += Method2;  // 第三个方法

输出如下:

1
2
2

我们不仅可以加方法,还可以减方法:

Action action1 = Method1;  // 第一个方法
action1 += Method2;  // 第二个方法
action1 += Method2;  // 第三个方法
action1 -= Method1;  // 减去方法1

输出如下:

2
2

多播委托返回值

对于多播委托,返回值为最后一次执行的方法的返回值。
也正因如此,我们建议多播委托中的方法总是没有返回值。

将多播委托转换为委托数组

你可以认为,多播委托中存放了许多个方法,所以我们理应能将多播委托转为方法数组。实际上,C#中没有方法类型,只有委托类型,所以我们能将多播委托转换为委托数组,一个委托对应一个方法:

Delegate[] actionsArray = action1.GetInvocationList();  // 将多播委托转为委托数组

我们可以对委托数组中的委托遍历执行,但由于编译时并不能确定委托数量和其参数,所以在调用委托时要使用DynamicInvoke方法进行动态调用。

Delegate[] actionsArray = action1.GetInvocationList();  // 将多播委托转为委托数组
foreach (Delegate d in actionsArray)
{
    d.DynamicInvoke();  // 动态调用
}

由于我们前面action1中的两个方法参数都为空,所以DynamicInvoke方法参数也为空。在其他时候,你应当像一般情况调用委托一样,传入实参。
且对于DynamicInvoke方法,返回值为object类型,你应当用显式转换的方式转为其他类型,尽管多播委托一般无返回值,但这是需要注意的。

匿名方法

在学习Func委托前,我们希望定义一个委托,使其返回值为两个参数之和可以这么写:

static void Sum(int a, int b)
{
    return a + b;
}
delegate int SumDelegate(int a, int b);
SumDelegate sumDelegate = Sum;

学习Func委托后,可以简化为这样:

static void Sum(int a, int b)
{
    return a + b;
}
Func<int, int, int> sumDelegate = Sum;

现在,使用匿名方法,可以继续简化。
匿名方法的写法如下:

Func<int, int, int> sumDelegate = delegate (int a, int b) { return a + b; }

可以看到,原先的函数名被换为了delegate (参数) {函数体},这么写,我们就可以在不写方法名的情况下从委托对象中使用方法,这也就是匿名方法。

你也可以扩展函数体,但是匿名方法一般用于函数体简单的情况,其余情况用一般方法即可。

Lambda表达式

Lambda表达式一般与匿名方法同时使用。
例如上面的简化,用Lambda表达式的书写如下:

Func<int, int, int> sumDelegate = (a, b) => a + b;

可以看到,书写格式变成了下面这样:

委托类型 委托名 = (参数1, 参数2, 参数n...) => 函数体;

对于Lambda表达式,一般情况下函数体只有一行,所以你不需要加大括号。
对于参数,你不需要指定类型,类型会从委托中自行对应。
对于只有一行的返回值代码,可以不写return,参考上面的例子。

使用Lambda表达式,可以大大简化简单情况下的方法定义,让代码更为简洁。

先写到这里!