C#委托与Lambda表达式

一、自定义委托

委托是C#语言特有的语法,它是一种引用类型,表示对具有特定参数列表和返回类型的方法的引用。 在实例化委托时,你可以将其实例与任何具有兼容签名和返回类型的方法相关联。 你可以通过委托实例调用方法。
委托是安全封装方法的类型,类似于 C 和 C++ 中的函数指针。 与 C 函数指针不同的是,委托是面向对象的、类型安全的和可靠的。 委托的类型由委托的名称确定。 以下示例声明名为 Del 的委托,该委托可以封装采用Del作为参数并返回 void 的方法:

public delegate void Del(string message);

委托必须先声明,才能使用;委托对象通常可采用两种方式进行构造,一种是提供委托将封装的方法的名称,另一种是使用 lambda 表达式。

上面自定义委托声明好后就可以实例化这个委托

Del d = new Del(DelegateMethod);
d.Invoke("你好");
//下面是DelegateMethod方法
public static void DelegateMethod(string message)
{
    Console.WriteLine(message);
}

在实例化委托时必须要将要委托的方法名带入,如:Del d = new Del(DelegateMethod);中的**DelegateMethod **实际上是该方法的首地址:也就是指针所指DelegateMethod()方法的首地址,在实例化后 d 委托变量内存中所存储的是DelegateMethod()方法的首地址。
委托类型派生自 .NET 中的 Delegate 类。 委托类型是密封的,它们不能派生自 ,也不能从其派生出自定义类。 由于实例化的委托是一个对象,因此可以作为参数传递或分配给一个属性。 这允许方法接受委托作为参数并在稍后调用委托。 这被称为异步回调,是在长进程完成时通知调用方的常用方法。 当以这种方式使用委托时,使用委托的代码不需要知道要使用的实现方法。 功能类似于封装接口提供的功能。

总结

1、委托必须先声明在使用;

2、委托使用必须实例化,在实例化后要把委托的方法名带入;

3、委托的调用必须与委托的方法参数一致;

二、泛型与多播委托

多播委托广泛用于事件处理中。 事件源对象将事件通知发送到已注册接收该事件的接收方对象。 若要注册一个事件,接收方需要创建用于处理该事件的方法,然后为该方法创建委托并将委托传递到事件源。 事件发生时,源调用委托。 然后,委托将对接收方调用事件处理方法,从而提供事件数据。 给定事件的委托类型由事件源确定。

1、泛型委托的声明

// 声明一个泛型委托
public delegate T myDelegate <T>(T x, T y);

2、泛型委托的调用

下面展示一些 内联代码片

//实例化委托
 myDelegate<int> myd = new myDelegate<int>(Add);//
 int res1 = myd(200, 3000);
 Console.WriteLine(res1);
 Console.ReadLine();
 //调用时,委托可以调用多个方法。 这被称为多播。 
 //若要向委托的方法列表(调用列表)添加其他方法,
 //只需使用加法运算符或加法赋值运算符(“+”或“+=”)添加两个委托。
 myd += Mul;
 int res2 = myd(200, 3000);
 Console.WriteLine(res2);
 Console.ReadLine();
 MyMul myMul = new MyMul();
 //多播委托
 myd += myMul.Mul;
 int res3 = myd(200, 200);
 Console.WriteLine(res3);
 Console.ReadLine();

3、泛型委托调用的方法

下面展示一些 内联代码片

 //委托要调用的方法——1
static int Add(int x, int y)
{
     return x + y;
 }
 //委托要调用的方法——2
 static int Mul(int x,int y)
 {
     return x * y;
 }
class MyMul
{
委托要调用的方法——3
  public int Mul(int x, int y)
  {
      return x * y;
  }
 }

三、 Action 委托

您可以使用Action 委托以参数的形式传递方法,而无需显式声明自定义委托。 封装的方法必须对应于由此委托定义的方法签名。 这意味着封装的方法必须没有任何参数,并且不能有返回值。 (在 c # 中,该方法必须返回 void 。)
下面展示一些 内联代码片

// Action 委托
 Action action_1 = new Action(M1);
 action_1.Invoke();
 Console.WriteLine();
 Console.ReadLine();
 //Action 委托要调用的方法
static void M1()
{
     Console.WriteLine("Hello Word");
     
 }

注意:若要引用没有参数并返回值的方法,请改用泛型 Func 委托。

四、 Action 泛型委托

1、没有返回参数的委托

可以使用 Action 委托以参数形式传递方法,而无需显式声明自定义委托。 封装的方法必须对应于由此委托定义的方法签名。 这意味着,封装的方法必须具有一个通过值传递给它的参数,并且它不能返回值。 (在 c # 中,该方法必须返回 void 。)
下面展示一些 内联代码片

 Action<string> action_2 = new Action<string>(M2);
 action_2.Invoke("张三");
 Console.WriteLine();
 Console.ReadLine();
 //要调用的方法
 static void M2(string name)
 {
      Console.WriteLine($"Hello Word ,+{name}");

  }

2 使用有返回参数的委托

下面展示一些 内联代码片

// 使用有返回参数的委托_1
 Func<int, int, int> func_1 = new Func<int, int, int>(Add);
 int resutl_1 = func_1(200, 300);
  Console.WriteLine(resutl_1);
  Console.ReadLine();
  //调用方法
static int Add(int x, int y)
{
    return x + y;
}

五、 Func 泛型委托

1、有返回值无参数Func 泛型委托

您可以使用此委托来表示一个方法,该方法可作为参数传递,而无需显式声明自定义委托。 封装的方法必须对应于由此委托定义的方法签名。 这意味着封装的方法必须没有任何参数,并且必须返回值。

Func<int> action_5 = new Func<int>(ReturnInt);
int res_5 = action_5.Invoke();
 Console.WriteLine(res_5);
 Console.ReadLine();
 static int ReturnInt()
 {
     int x = 100;
     int y = 100;
     return x * y;
 }

2、有返回值有参数Func 泛型委托

 Func<int, int, int> func_1 = new Func<int, int, int>(Add);
	int resutl_1 = func_1(200, 300);
 	Console.WriteLine(resutl_1);
 	Console.ReadLine();
 static int Add(int x, int y)
 {
      return x + y;
  }

六、 Lambda表达式委托

1、Lambda表达式的使用

 Func<int, int, int> funcLambda_1 = new Func<int, int, int>((int x,int y )=> { return x + y; });
int res_1 = funcLambda_1.Invoke(500,500);
Console.WriteLine(res_1);
Console.ReadLine();

2、Lambda表达式的简化过程_1

 Func<int, int, int> funcLambda_2 = new Func<int, int, int>((x, y) => { return x + y; });
 int res_2 = funcLambda_1.Invoke(500, 500);
  Console.WriteLine(res_2);
  Console.ReadLine();

3、Lambda表达式的简化过程_2

 Func<int, int, int> funcLambda_3 = (x, y) => { return x + y; };
 int res_3 = funcLambda_3.Invoke(500, 500);
 Console.WriteLine(res_3);
 Console.ReadLine();

七、 泛型委托的综合使用

1、泛型委托的综合使用(没有返回参数)_1

Target_1<int>((x,y)=> { return x + y; },200,300);
static void Target_1<T>(Func<T,T,T> func,T x, T y)
{
     T res = func(x, y);
     Console.WriteLine(res);
     Console.ReadLine();
 }

2、泛型委托的综合使用(有返回参数)_2

int resutl = Target_2<int>((x, y) => { return x + y; }, 2000, 3000);
Console.WriteLine(resutl);
 Console.ReadLine();
static T Target_2<T>(Func<T, T, T> func, T x, T y)
{
    T res = func(x, y);
    return res;
}

在方法重载的上下文中,方法的签名不包括返回值。 但在委托的上下文中,签名包括返回值。 换句话说,方法和委托必须具有相同的返回类型。
将方法作为参数进行引用的能力使委托成为定义回调方法的理想选择。 可编写一个比较应用程序中两个对象的方法。 该方法可用在排序算法的委托中。 由于比较代码与库分离,因此排序方法可能更常见。

八、 何时使用委托而不使用接口

委托和接口都允许类设计器分离类型声明和实现。 任何类或结构都能继承和实现给定的接口。 可以为任何类上的方法创建委托,前提是该方法符合委托的方法签名。 接口引用或委托可由不了解实现该接口或委托方法的类的对象使用。 既然存在这些相似性,那么类设计器何时应使用委托,何时又该使用接口呢?

在以下情况下,请使用委托:

1、当使用事件设计模式时。

2、当封装静态方法可取时。

3、当调用方不需要访问实现该方法的对象中的其他属性、方法或接口时。

4、需要方便的组合。

5、当类可能需要该方法的多个实现时。

在以下情况下,请使用接口:

1、当存在一组可能被调用的相关方法时。

2、当类只需要方法的单个实现时。

3、当使用接口的类想要将该接口强制转换为其他接口或类类型时。

4、当正在实现的方法链接到类的类型或标识时:例如比较方法。

IComparable 或泛型版本 IComparable 就是一个使用单一方法接口而不使用委托的很好的示例。 IComparable 声明 CompareTo 方法,该方法返回一个整数,指定相同类型的两个对象之间的小于、等于或大于关系。 IComparable 可用作排序算法的基础。 虽然将委托比较方法用作排序算法的基础是有效的,但是并不理想。 因为进行比较的能力属于类,而比较算法不会在运行时改变,所以单一方法接口是理想的。

  • 2
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

杏雨1969

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值