十七 关于委托

本文深入探讨C#中的委托概念,包括其与JavaScript回调的相似性,如何定义和使用委托,协变逆变的原理,以及委托链的实现。同时,文章对比了委托与接口的优劣,并介绍了泛型委托的使用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

先看委托。 然后事件 当然可耻的直接用了书的源码。

首先.. 委托就和js中得回调一样,别人都用c举例...本人只能用js举例。。。。 ╮(╯▽╰)╭

function a(func)
{
  var el= document.body;
   func(el)
}
function b(el) { do something.. }
a(b); 

委托也是这样.. 不过要麻烦很多.

internal delegate void Feedback(Int32 value); 先定义
public static void Main()
{
   Counter(
1, 3, new Feedback(FeedbackToConsole)); //这是调用... 同样是将方法传入
  
//Counter(1, 3, Program.FeedbackToConsole); //这样也是可以的
}

private
static void Counter(Int32 from, Int32 to, Feedback fb)
{
for (Int32 val = from; val <= to; val++)
{
if (fb != null)
fb(val);
}
}

private static void FeedbackToConsole(Int32 value)
{
Console.WriteLine(
"Item=" + value);
}

关于协变 逆变

协变 就是委托返回的类型是派生类

逆变 就是返回基类..

当然 他们只能针对值类型

internal delegate object Feedback(Int32 value); 

你绑定的方法可以是 string aaa(int i);

不过关于协变逆变的性能以后再讨论


前面调用的都是静态方法,这里传了一个实例,当然只是把栈中得地址传了过去

private static void InstanceDelegateDemo()
{
Program p = new Program();
Counter(
1, 3, new Feedback(p.FeedbackToFile)); //这里传递的是引用..
Console.WriteLine();
}

  

关于写法. 委托从1.0到现在写法有一些变化..

internal delegate void Feedback(Int32 value);

public static void Main()
{
Counter(1, 3, new Feedback(FeedbackToMsgBox)); 1.0
Counter(1, 3, delegate(int a)  2.0 
{ 
   //匿名方法
  //你不必单独创建方法 就像上面的FeedbackToMsgBox,当然这玩意儿得建立在你只在这里使用
  //感觉上就像闭包. 当然前提是他得引用上下文..
  //当然简便代码是很重要的,很多时候调用方法需要传入一个委托, 没有他你就麻烦了。。
  //也有缺点。 毕竟像过多外部参数 维护起来 啊哈
});

Counter(1,3, a => a++); 3.5
//貌似生成的代码是一个匿名方法 摊手..

//适当的使用委托(包括 匿名方法,lamb), 能让代码更优美~~~~~~~~~
}
private static void Counter(Int32 from, Int32 to, Feedback fb){}

  


关于他里面干了什么?

首先看IL.. 虽然看的恼火

internal delegate void Feedback(Int32 value);

.class auto ansi sealed nested assembly Feedback
extends [mscorlib]System.MulticastDelegate
{
.method
public hidebysig specialname rtspecialname instance void .ctor(object 'object', native int 'method') runtime managed
{
}
.method
public hidebysig newslot virtual instance class [mscorlib]System.IAsyncResult BeginInvoke(int32 'value', class [mscorlib]System.AsyncCallback callback, object 'object') runtime managed
{
}
.method
public hidebysig newslot virtual instance void EndInvoke(class [mscorlib]System.IAsyncResult result) runtime managed
{
}
.method
public hidebysig newslot virtual instance void Invoke(int32 'value') runtime managed
{
}
}

继承自 System.MulticastDelegate

第一个是一个构造

所有委托都有构造器,参数一个是 object 一个是int
开始我以为是传得参数,毕竟委托的参数也是int,后来重新写了一个 string参数的委托,发现构造的参数还是int。 忧郁。

Object是引用对象(引发装箱拆箱
?),如果传入的是静态方法 Object 会是null

Int 据书上说是 标识了方法的一个特殊值...

然后 在构造器内部
object 和 Int 分别保存在_target _methouPtr

  

然后一个和原型一样的方法

这玩意就是调用原方法的方法.. 委托都会隐式的调用他.

然后就是三个变量

之前上面提到了

_target //如果你传入的不是静态方法, 那这个就存放你传进来的方法所属的类
_methouPtr //只是一个整数值,标示回调的方法
_invocationList //数组. 通常是null 只有在委托链的时候

关于委托链

Console.WriteLine("----- Chain Delegate Demo 1 -----");
Feedback fb1
= new Feedback(FeedbackToConsole);
Feedback fb2
= new Feedback(FeedbackToMsgBox);
Feedback fb3
= new Feedback(p.FeedbackToFile);

Feedback fbChain
= null;
fbChain
= (Feedback)Delegate.Combine(fbChain, fb1);
fbChain
= (Feedback)Delegate.Combine(fbChain, fb2);
fbChain
= (Feedback)Delegate.Combine(fbChain, fb3);
Counter(
1, 2, fbChain);

Console.WriteLine();
fbChain
= (Feedback)Delegate.Remove(fbChain, new Feedback(FeedbackToMsgBox));
Counter(
1, 2, fbChain);

书上的例子很明确了
在添加的时候
_invocationList [0,1,2] 分别代表的3个委托,所以在 Counter执行的时候 会分别调用那3个委托
同样 也提供了Remove 删除不用的

当然也有简便方法
fbChain += fb1;
fbChain += fb2;
fbChain += fb3;

fbChain.GetInvocationList(); 返回Delegate[] over~

泛型委托

internal delegate void Feedback(T value); //只是一个T~ 其他不变

关于泛型这里就不赘述了 会在之后的写 到时候再反过来加链接吧


ok 谈谈委托的使用

其实都知道 委托在很多程度上可以用 接口来代替, 只是每次都弄个类 搞个接口 确实比较繁琐

委托给人的感觉就是不知道使用者要干什么,如果上下文清楚 个人感觉使用接口要好一点(当然,这对我来说只是规范问题)

其实这里还差一段代码... 就是测试 委托 和 接口..  在处理相同的时候的效率问题

本人思来想去 还是觉得自己的测试方法不太好, 暂时搁置一下吧. 想到了再说

ok 之前是我的观点.

还有一种观点就是,这些性能损失在实际代码中是微乎其微的.

而是应该在性能和可读性,可维护性上找到一个平衡点

不可否认 lamb表达式的正确使用确实让代码易懂和优美。

 a.Select(lamb)
.Where(lamb)
.OrderBy(
lamb)
.ToList();


当你使用它的时候有些东西需要注意
1. 这一连串的方法,他当时不会执行,只会在你调用的时候才会执行~
2. 他是循环执行的 第一个元素 select - where - select - orderBy - 第二个元素 重复..
3. 就是他得延迟性(这玩意儿..我没有研究)

有兴趣的可以去看看 姐夫赵的 从.NET中委托写法的演变谈开去(下):性能相关

特别是在使用官方提供的方法的时候,lamb的优势极其明显

当然也有缺点 比如调试,lamb表达式无法调试,所以建议在lamb表达式中不要有复杂逻辑,要不然调试起来够你折腾

over








转载于:https://www.cnblogs.com/CallMeTommy/archive/2011/08/28/2148662.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值