C函数指针到C#委托

C语言中的指针

    C语言中的指针像潘多拉魔盒一样让人又爱又恨,其实可以将指针理解为一种数据类型,比如int就是内置的一种数据类型,而指针与int类似都是一种数据类型,int类型又可分为int_32,int_64,而指针类型其中一个就是函数指针。函数指针的使用示例如下:

#include <stdio.h>
// 1.typedef 的作用是给数据类型起一个新的名字,此处FunctionPoint就是函数指针类型的别名
typedef int (*FunctionPoint)(int,int);
// 2.函数指针的使用
// 2.1 实现测试函数,函数签名要与函数指针类型的函数签名一致
int test(int a,int b)
{
	return a+b;
}
int main()
{
	// 2.2 将test函数赋值给FunctionPoint声明的变量
	FunctionPoint function = test;
	// 2.3 调用 此语句将最终调用到test函数
	int result = function(1,2);
	printf("%d",result);
	return 0;
}

C#中的委托

从上面C的例子中我们大概可以认识到,函数指针可以像整型(int)一样,定义变量,并对其赋值然后进行使用。

在C#中同样可以实现与C语言中相同的功能,而且功能更加丰富,那就是通过C#中的委托(Delegate),可以简单的将理解为是函数指针的升级版。关于委托的官方介绍如下:

委托是一种引用类型,表示对具有特定参数列表和返回类型的方法的引用。 在实例化委托时,你可以将其实例与任何具有兼容签名和返回类型的方法相关联。 你可以通过委托实例调用方法。

委托的声明

委托的声明需要使用到关键字delegate,示例如下:

public delegate int MyDelegate(int x, int y);

从反编译角度看委托

上面声明的委托类型经过ILSpy反编译后,会发现声明的委托类型实际上就是一个类,其中内容如下所示:

// IL代码
.class nested public auto ansi sealed MyDelegate
	extends [mscorlib]System.MulticastDelegate
{
	// 方法
	.method public hidebysig specialname rtspecialname 
		instance void .ctor (
			object 'object',
			native int 'method'
		) runtime managed 
	{
	} // 方法 MyDelegate::.ctor 结束

	.method public hidebysig newslot virtual 
		instance int32 Invoke (
			int32 x,
			int32 y
		) runtime managed 
	{
	} // 方法 MyDelegate::Invoke 结束

	.method public hidebysig newslot virtual 
		instance class [mscorlib]System.IAsyncResult BeginInvoke (
			int32 x,
			int32 y,
			class [mscorlib]System.AsyncCallback callback,
			object 'object'
		) runtime managed 
	{
	} // 方法 MyDelegate::BeginInvoke 结束

	.method public hidebysig newslot virtual 
		instance int32 EndInvoke (
			class [mscorlib]System.IAsyncResult result
		) runtime managed 
	{
	} // 方法 MyDelegate::EndInvoke 结束

} // 类 MyDelegate 结束

可以从IL代码中提取到的关键信息如下:

  1. 委托类型最终的内部表现是一个类
  2. 委托继承MulticastDelegate
  3. 委托内置的方法Invoke,BeginInvoke()及EndInvoke

多播委托

C#中的委托本质是一个类,是一个对象,那么这个对象就可以封装各种各样的功能,其中多播委托就是一个经典的功能。多播委托的注册使用"+=",多播委托的删除使用"-=",以注册多播委托为例:

// 创建委托实例
MyDelegate myDelegate = new MyDelegate(TestAdd);
// 注册多播委托
myDelegate += TestSub;

多播委托的调用由两种方式

  • 第一种全部调用
// 执行委托,result的结果为TestSub执行结果
int result = myDelegate(1, 2);
  • 第二种遍历调用(可根据需求具体调用那个)
Delegate[] delegates = myDelegate.GetInvocationList();
foreach (MyDelegate item in delegates)
{
    item(2, 2);
}

异步委托

委托的执行默认采用Invoke方式执行(同步方式调用),然而委托也可采用异步方式执行,使用BeginInvoke就可以异步方式执行:

// BeginInvoke的最后两个参数固定为AsyncCallback和object,前面剩余的参数和要执行的异步方法的参数列表一致
// AsyncCallback定义异步执行完成以后要执行的函数
// object为传入的状态在AsyncCallCompleted中可获取到
public static void AsyncCallCompleted(IAsyncResult ar)
{
    //获取BeginInvoke传入的的state参数
    string strState = (string)ar.AsyncState;
    Console.WriteLine("传入的字符串是{0}", strState);
}
// 执行异步委托
IAsyncResult res = myDelegate.BeginInvoke(3, 3, new AsyncCallback(AsyncCallCompleted), "测试程序");
myDelegate.EndInvoke(res);
// 注:调用完BeginInvoke以后一定要调用EndInvoke

结束异步委托的常见四种场景

  1. 做一些其他操作,然后调用EndInvoke方法阻塞线程直到该方法完成。
  2. 使用IAsyncResult.AsyncWaitHandle属性,使用它的WaitOne方法阻塞线程直到收到WaitHandle信号,然后调用EndInvoke。
  3. 检查BeginInvoke返回值IAsyncResult的状态来决定方法是否完成,然后调用EndInvoke方法。
  4. 通过在BeginInvoke方法中传递AsyncCallback的回调方法中调用该委托的EndInvoke方法。(推荐)

C#默认封装好的委托

Action&Func

Action委托与Func委托最主要的区别在于,Action委托没有返回值,Func委托允许由返回值 参考

关注「CoderPro」公众号 ,在微信后台回复「C#委托」,获取示例代码
在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值