编程语言中高级特性:委托

形象的理解什么是委托

顾名思义,委托,把事情托付给他人或机构(办理)。诸如:“当事人委托律师出庭辩护”,“我能委托你办一件事吗”。总的来说就是委托方将具体的事情交给被委托方来做, 委托方不关心具体过程,只关心开始和结果。被委托方执行具体内容即可。

委托的使用会经历如下的过程

  • 委托的声明: 定义委托内容中需要什么,达到什么样的效果。定义出庭辩护
  • 编写委托方法: 按照定义的标准, 详细制定委托内容。出庭辩护的内容
  • 实例化委托: 创建委托实例。某个律师有出庭辩护的资格
  • 调用委托: 被委托人执行委托内容。这个律师执行辩护, 并将结果返回给当事人

委托可以将方法封装为其它方法的参数

委托(Delegate)特别用于实现事件回调方法。所有的委托(Delegate)都派生自 System.Delegate 类。

委托的使用

声明委托

前面我们知道委托都是派生自System.Delegate 类, 所以委托是个类哦~

// 和接口方法声明一样, 只不过多了个delegate关键字, 注意没有方法体
public delegate int ShowDelegate(int a, int b);

另外, c#自带了两种委托, 如果你在程序中使用, 那么可以省略声明步骤

Action<参数1,... 参数N> // 无返回值的委托
Func<参数1,... 参数N> // 有返回值的委托(必须有返回值)

当然, 委托的类型可以是泛型, 表示泛型委托, 泛型委托极大的提高了代码的扩展性。

编写委托方法

按照委托声明编写委托方法, 同普通方法一样即可

public static int AddNum(int a, int b)
{
    // 方法内容
}

实例化委托

// 方式一: 通过new 委托 来实例化
ShowDelegate sd = new ShowDelegate(AddNum)
// 方式二: 使用赋值的方式
ShowDelegate sd = AddNum
// 方式三: 匿名委托, 这种方式 委托方法写在匿名委托中
ShowDelegate sd = delegate(int s, int v){
    Console.WriteLine($"匿名委托,{s}&{v}");
}
// 方式四: 使用Lambda, 这种方式 委托方法写在Lambda中
ShowDelegate sd = (int s, int v) => { Console.WriteLine($"Lambda,{s}&{v}"); };

调用委托

// 方式一: 同步调用
sd(1, 2)

// 方式二: 同步调用
sd.Invoke(1, 2);

// 方式三: 异步调用
IAsyncResult iar = sd.BeginInvoke(3,4,null,null); // 异步调用
int result = sd.EndInvoke(iar);    // 获取异步执行结果

完整代码

using System;

// 1.声明委托
delegate int ShowDelegate(int a, int b);
namespace DelegateAppl
{
   class TestDelegate
   {
      static int num = 10;
      // 2.编写委托方法
      public static int AddNum(int m, int n)
      {
         num += m;
         num += n;
         return num;
      }
      public static int AddNum1(int m, int n)
      {
         num += m;
         num += n;
         return num;
      }
      public static int getNum()
      {
         return num;
      }
      static void Main(string[] args)
      {
         // 3.创建委托实例
         ShowDelegate nc1 = new ShowDelegate(AddNum);
         nc1 += AddNum1; // 委托的多播, 这里的nc1绑定了两个委托
         ShowDelegate nc2 = new ShowDelegate(AddNum1);
         // 4.使用委托对象调用方法
         nc1(1, 2);
         Console.WriteLine("Value of Num: {0}", getNum());
         nc2(3, 4);
         Console.WriteLine("Value of Num: {0}", getNum());
         Console.ReadKey();
      }
   }
}

Action、Func、Predicate委托

// Action、Func、Predicate委托

// 无参数无返回值
// lambda实现委托实例
Action a1 = () => Console.WriteLine(1);
a1();

// delegate实现委托实例,下面不再演示delegate。
Action a2 = delegate { Console.WriteLine(1); };
a2();

// 有参数无返回值
Action<int> a3 = (x) => Console.WriteLine(x);
a3(1);

// 无参数有返回值的情况
Func<int> e1= ()=> 1;
var value1= e1();

// 有参数有返回值的情况
// 最后一个泛型是返回值的类型
Func<int,int> e2 = (x) => x+1;
int value2= e2(1);

// 多参数情况
Func<int, int,int> e3 = (x,x2) => x+x2 + 1;
int value3 = e3(1,2);

// 返回值是布尔类型
// 其实Predicate可以用Func返回值是bool来代替的。
Predicate<int> p = (x) => x > 0;
bool value4 = p(1);

委托的多播

可以理解成, 当事人既委托律师去打官司, 又委托同一个律师去保释

// 可以使用 变量 += 委托 或 变量 -= 委托 进行添加和删除委托

委托与函数指针

委托是从函数指针中发展而来, 但不像函数指针那样直接记录某函数的"门牌号码"和解析规则以供间接调用函数;而是以面向对象的方式定义一个类,这个类描述的是符合某种特征的方法,而这个类的对象可以作为参数被其它方法调用;委托当然也可以被直接调用。(因为委托的实例封装着方法,委托实例就是一种特殊的方法)

C#中的委托与函数指针在某些方面是有相似之处的,但也存在一些本质上的区别。

相似之处:

  • 引用函数:委托和函数指针都可以用来引用函数。委托在C#中是一种类型,可以将方法引用存储在委托对象中,而函数指针在C#中可以通过使用unsafe关键字和delegate*指针类型来实现。

  • 调用函数:委托和函数指针都可以用于调用函数。通过委托的Invoke()方法或者直接使用函数指针的调用语法,可以调用被引用的函数。

不同之处:

  • 类型安全性:C#的委托是类型安全的,编译器会在编译时进行类型检查,确保委托的签名与引用的方法匹配。而函数指针在C#中需要使用unsafe关键字,并且不会进行类型检查,因此可能存在潜在的类型不匹配问题。

  • 语法和语义:委托使用delegate关键字声明,并且可以使用多播委托来引用多个方法。而函数指针在C#中需要使用unsafe关键字声明,并且不能直接引用多个函数。

  • 托管环境:委托是.NET框架的一部分,受到托管环境的管理和限制。而函数指针是在C#中使用unsafe代码块来实现的,并且不受托管环境的控制。

总结:
委托是C#中的一种类型,用于引用和调用方法,具有类型安全性、多播功能等特点。函数指针是在C#中使用unsafe关键字声明的指针类型,可以用于引用和调用函数,但需要注意类型安全性和托管环境的影响。委托是更常用、更推荐的一种机制,而函数指针在特定的场景下使用。

委托与回调函数

委托和回调函数在C#中常常一起使用,但它们是不同的概念和机制。

委托(Delegate)是一种类型,用于存储对方法的引用。通过定义委托类型,可以声明委托对象,并将其关联到特定的方法。委托允许您将方法作为参数传递,并在需要时调用该方法。它提供了一种实现回调机制的方式。可以将委托视为一个函数指针,它允许您以类型安全的方式引用和调用方法。

回调函数(Callback Function)是一种机制,其中函数可以作为参数传递给其他函数,并在需要时被调用。回调函数常用于异步操作或事件处理中。在C#中,回调函数通常通过委托来实现。通过将回调函数作为委托类型的参数传递给某个方法,当需要的时候,可以调用委托来执行回调函数。

委托和回调函数的关系如下:

  • 委托可以用于存储对回调函数的引用。通过声明一个委托类型,可以创建委托对象,并将其关联到特定的方法,这个方法就是回调函数。
  • 当需要执行回调操作时,可以通过调用委托对象来触发回调函数的执行。

通过委托和回调函数的组合,可以实现解耦和灵活性。委托允许您在运行时动态选择要执行的方法,而回调函数提供了一种向其他代码传递函数的能力。这种组合可以用于处理异步操作、事件处理、插件系统等各种场景

无论是C#中的委托还是JavaScript中的函数赋值给变量,都可以通过调用变量来执行相应的函数。这种方式可以方便地将函数作为值进行传递、存储和调用。委托和JavaScript中的函数都允许将函数作为一等公民对待,使得函数可以像其他数据类型一样进行操作。

扩展阅读

C#委托事件机制:函数指针——委托的由来(2)

此处评论已关闭