C# 委托(delegate) 详解

2025-12-13 0 362

概念:
类似C/C++的函数指针。委托是一种引用类型变量, 存有一系列对象方法的地址,是对一系列方法的引用的一种引用类型变量。调用委托的时候,它所引用的所有方法都会被执行

通俗来说。委托对象是用来存放某一类别的方法调用清单,这一类别要求方法签名(方法的参数,返回值)与委托类型签名一致。当这个清单被调用时,清单内的方法也会依次执行

.NET 自带的委托
.NET提供了两个自带的委托类型。两种委托类型已经能够胜任绝大部分开发需求。它们分别是 Action<T>与Func<T,TResult> 委托。
=>T:此委托封装的方法的参数类型。
=>TResult:此委托封装的方法的返回值类型。
T与TResult都为逆变类型参数。即,可以使用指定的类型,也可以使用派生程度更低的类型。

两种委托类型的区别是什么?
对于一个没有返回值的方法,应该使用Action封装。如果一个方法带有返回值 则使用Func。

Action委托
1.简单举例:

internal class Program
{
static void Main(string[] args)
{
Boy boy = new Boy(\”Jack\”);
Action a1 = new Action(boy.Eat);
a1.Invoke();

Action<int> a2 = new Action<int>(boy.Sleep);
a2(10);
}

class Boy
{
public Boy(string name)
{
Name = name;
}

public string Name { get; set; }
public void Eat()
{
Console.WriteLine($\”男孩 {Name} 正在吃东西…\”);
}

public void Sleep(int time)
{
Console.WriteLine($\”男孩 {Name} 一共睡了 {time} 小时\”);
}
}

}
此例声明一个Boy类 中含有两个方法。Eat方法无参数,Sleep需要一个Int参数.且都无返回值。
如果需要使用Action包装boy的两个方法我们就需要声明与此方法相同的签名的Action对象。如上例所示 分别声明了两个签名与方法相同的Action对象。

2.对于委托对象时有几种不同的声明方式和调用方式,下面出了举例:

Action a1 = new Action(boy.Eat);//声明方式1
Action a2 = boy.Eat;//声明方式2
Action a3 = () => {//声明方式3
boy.Eat();
Console.WriteLine(\”Lambda表达式声明…\”);
a1.Invoke();//调用方式1
a2();//调用方式2

};

声明方式: 1.new关键字 2.直接赋值 3.Lambda表达式

调用方式: 1.对象名.Invoke(参数) 2.对象名(参数)

3.下面是对Action对象的一些定义案例
Action委托至少0个参数,至多16个参数,无返回值。
Action 表示无参,无返回值的委托。
Action<int,string> 表示有传入参数int,string无返回值的委托。
Action<int,string,bool> 表示有传入参数int,string,bool无返回值的委托。
Action<int,int,int,int> 表示有传入4个int型参数,无返回值的委托。

Func委托
1.简单举例

static void Main(string[] args)
{
Boy boy = new Boy(\”Jack\”);
Func<int,int,int> f1 = new Func<int, int, int>(boy.DoSum);
Console.WriteLine(f1.Invoke(1,1));

Func<double, double, double> f2 = new Func<double, double, double>(boy.DoDiv);
Console.WriteLine(f2.Invoke(10,3));
}

class Boy
{
public Boy(string name)
{
Name = name;
}

public string Name { get; set; }

public int DoSum(int x,int y)
{
return x + y;
}

public double DoDiv(double x, double y)
{
return x / y;
}
}

上例中定义了两个方法,方法分别有着不同的返回值类型。在声明func委托时应该注意签名的一致。
DoSum返回值为int,并且拥有两个int类型参数。所以使用委托类型Func<int,int,int>(此处的第一个int为TResult即返回值类型)
DoDiv返回值为double,并且拥有两个int类型参数。所以使用委托类型Func<double,int,int>(此处的第一个int为TResult即返回值类型)

自定义委托(delegate)
首先要撇清的关系
delegate和Delegate的区别
1.Delegate 是一个不折不扣的类。
2.delegate 是关键字,用来声明委托类。
3.类 Delegate 是委托类型的基类。 但是,只有系统和编译器才能从 Delegate 类或 MulticastDelegate 类显式派生。 此外,不允许从委托类型派生新类型。

声明
因为委托delegate是一种类。所以声明时请与class同级,一般情况下不需要嵌套class声明委托类。
1.委托类声明格式:
修饰符 delegate 返回值类型 委托名 ( 参数列表 );
举个栗子:
public delegate void Mydelegate();

2.声明此委托对象的格式:
委托名 委托对象名 = new 委托名 ( 方法名 );
举个栗子:
Mydelegate d1 = new Mydelegate( 方法名 );
这里需要注意方法与委托对象签名的一致性

简单示例
public delegate int Mydelegate(int a, int b);
internal class Program
{
static void Main(string[] args)
{
Boy boy = new Boy(\”jack\”);
Mydelegate dosum = new Mydelegate(boy.DoSum);
Console.WriteLine(dosum(1,5));
}

class Boy
{
public Boy(string name)
{
Name = name;
}

public string Name { get; set; }

public int DoSum(int x,int y)
{
return x + y;
}

}

}

为了与public int DoSum(int x,int y)有相同的签名。此处声明了返回值为int 同时带两个参数为int的委托类 Mydelegate

合并委托(多播)
概念
在概念中说过。委托对象是用来存放一系列方法的调用清单,这说明一个委托对象中可以同时存放多个方法。但前提是方法的签名必须与委托一致。
使用+=和-=操作符来添加/删除委托中的方法
格式:
委托对象 += 方法名
委托对象 -= 方法名

简单举例
public delegate void Mydelegate();
internal class Program
{
static void Main(string[] args)
{
Boy boy = new Boy(\”jack\”);
Mydelegate d1 =new Mydelegate(boy.DoHomeWork);
d1+= boy.Jump;
d1+= boy.Think;
d1.Invoke();
}

class Boy
{
public Boy(string name)
{
Name = name;
}

public string Name { get; set; }

public void DoHomeWork()
{
Console.WriteLine($\”{Name} 正在做作业…\”);
}

public void Jump()
{
Console.WriteLine($\”{Name} 正在跳…\”);
}

public void Think()
{
Console.WriteLine($\”{Name} 正在思考…\”);
}
}

}

输出:
jack 正在做作业…
jack 正在跳…

jack 正在思考…

异步委托与同步委托
前排提示
??前排提示:异步委托在.net core中已经被砍掉
详细相关:
https://devblogs.microsoft.com/dotnet/migrating-delegate-begininvoke-calls-for-net-core/

概念
上文中提过调用委托的方式有这样一种 => 委托对象.Invoke()
委托对象.Invoke() 是以同步委托的方式来调用此方法
此外还有另一种 =>委托对象.Begininvoke()

1.同步委托调用 Invoke()
2.异步委托调用 Begininvoke(callback,object)

同步委托上文已经提过。下文主要提提异步委托

BeginInvoke 方法启动异步调用。 该方法具有与你要异步执行的方法相同的参数,另加两个可选参数。 第一个参数是一个 AsyncCallback 委托,此委托引用在异步调用完成时要调用的方法。 第二个参数是一个用户定义的对象,该对象将信息传递到回调方法。 BeginInvoke 将立即返回,而不会等待异步调用完成。 BeginInvoke 返回可用于监视异步调用的进度的 IAsyncResult。

简单示例
internal class Program
{
static void Main(string[] args)
{
Boy boy1 = new Boy(“Jack”, ConsoleColor.DarkBlue);
Boy boy2 = new Boy(“Bob”, ConsoleColor.Red);
Boy boy3 = new Boy(“Anna”, ConsoleColor.Yellow);
Action a1 = boy1.DoHomeWork;
Action a2 = boy2.DoHomeWork;
Action a3 = boy3.DoHomeWork;
a1.BeginInvoke(boy1.FinshWork,boy1.Name);
a2.BeginInvoke(boy1.FinshWork, boy2.Name);
a3.BeginInvoke(boy1.FinshWork, boy3.Name);
}

class Boy
{
public Boy(string name, ConsoleColor penColor)
{
Name = name;
PenColor = penColor;
}

public string Name { get; set; }
public ConsoleColor PenColor { get; set; }

public void DoHomeWork()
{
for (int i = 0; i < 3; i++)
{
Console.WriteLine(Name+\”正在做第 \”+(i+1)+\” 个作业…\”);
Thread.Sleep(1000);
}
}

public void FinshWork(IAsyncResult ar)
{
Console.WriteLine(ar.AsyncState +\”做完了作业\”);
}

}
————————————————
版权声明:本文为CSDN博主「soar+」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_35652006/article/details/128928017

收藏 (0) 打赏

感谢您的支持,我会继续努力的!

打开微信/支付宝扫一扫,即可进行扫码打赏哦,分享从这里开始,精彩与您同在
点赞 (0)

申明:本文由第三方发布,内容仅代表作者观点,与本网站无关。对本文以及其中全部或者部分内容的真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。本网发布或转载文章出于传递更多信息之目的,并不意味着赞同其观点或证实其描述,也不代表本网对其真实性负责。

左子网 编程相关 C# 委托(delegate) 详解 https://www.zuozi.net/36531.html

常见问题
  • 1、自动:拍下后,点击(下载)链接即可下载;2、手动:拍下后,联系卖家发放即可或者联系官方找开发者发货。
查看详情
  • 1、源码默认交易周期:手动发货商品为1-3天,并且用户付款金额将会进入平台担保直到交易完成或者3-7天即可发放,如遇纠纷无限期延长收款金额直至纠纷解决或者退款!;
查看详情
  • 1、描述:源码描述(含标题)与实际源码不一致的(例:货不对板); 2、演示:有演示站时,与实际源码小于95%一致的(但描述中有”不保证完全一样、有变化的可能性”类似显著声明的除外); 3、发货:不发货可无理由退款; 4、安装:免费提供安装服务的源码但卖家不履行的; 5、收费:价格虚标,额外收取其他费用的(但描述中有显著声明或双方交易前有商定的除外); 6、其他:如质量方面的硬性常规问题BUG等。 注:经核实符合上述任一,均支持退款,但卖家予以积极解决问题则除外。
查看详情
  • 1、左子会对双方交易的过程及交易商品的快照进行永久存档,以确保交易的真实、有效、安全! 2、左子无法对如“永久包更新”、“永久技术支持”等类似交易之后的商家承诺做担保,请买家自行鉴别; 3、在源码同时有网站演示与图片演示,且站演与图演不一致时,默认按图演作为纠纷评判依据(特别声明或有商定除外); 4、在没有”无任何正当退款依据”的前提下,商品写有”一旦售出,概不支持退款”等类似的声明,视为无效声明; 5、在未拍下前,双方在QQ上所商定的交易内容,亦可成为纠纷评判依据(商定与描述冲突时,商定为准); 6、因聊天记录可作为纠纷评判依据,故双方联系时,只与对方在左子上所留的QQ、手机号沟通,以防对方不承认自我承诺。 7、虽然交易产生纠纷的几率很小,但一定要保留如聊天记录、手机短信等这样的重要信息,以防产生纠纷时便于左子介入快速处理。
查看详情

相关文章

猜你喜欢
发表评论
暂无评论
官方客服团队

为您解决烦忧 - 24小时在线 专业服务