面试中可能会被问到的几个关于“委托”的问题

王朝学院·作者佚名  2016-08-27
窄屏简体版  字體: 小  |  中  |  大  |  超大  

这几天比较清闲,刚好前段时间买了本CLR Via C#,在.Net界大家都知道Jeffrey大师的这本经典著作,惭愧一直没有拜读。

不过在C#著作中经典的非常多。读书的那时候就是通过《C#与.NET 3.0高级程序设计》这本书接触C#的,也被称为C#圣经。

CLR Via C#中的委托说的非常好,比较深入,让人耳目一新,回味无穷的感觉,看这本书的时候一定要记得带上ILDasm和

Reflector,有了他们就可以让我们更加深入的看一些问题,读书的方式有很多种,提问式的,提炼式的,因为任何东西都遵循

“八二原则“,100个字中,有营养的文字也就区区20个而已,抓住了就理解了,好了,就乱扯到这里了。

Q: 什么是委托

A: 委托就是一个继承自MulticastDelegate的类,不信可以用 ILdasm 看一下。

1publicdelegatevoidFlyAction();

Q: 我从ILdasm中看到了Invoke方法,但是我在Delegate却没有看到该方法的定义?为什么?

A: 这其实是混淆了delegate关键字和FCL中的Delegate类型,而对于delegate关键字,编译器和CLR给我们做了很多的优化,

并且掩盖了很多复杂的细节,而FCL中的Delegate并没有。

Q: 我知道可以将方法作为参数传递给委托,然后可以在任何地方通过委托的invoke来执行那个作为参数的方法,请问是如何做到的?

A:既然可以在任何地方引用这个参数的方法,那就要看看方法是如何入侵到委托的。

① 先看看实例代码:

1namespaceDemo2{3classPRogram4{5publicdelegatevoidFlyAction();67staticvoidMain(string[] args)8{9Bird bird =newBird();1011FlyAction action =newFlyAction(bird.Fly);1213action.Invoke();14}15}1617publicclassBird18{19publicstaticRandom rand =newRandom();2021publicvoidFly()22{23return"i can fly"+rand.Next();24}25}26}

从第一个QA中我们也看到了,其实委托是就是类,那我new一个类时,bird.fly其实就是类的构造函数的参数。

② 再来看看生成的IL中的构造函数。

这时候问题就出来了,为什么这里有两个参数,而new FlyAction(bird.Fly) 中却是一个参数,这里貌似是有问题的,不符合语法规

则,其实这里还是编译器提供了一个中间层,通过这个中间层做了一个转化,从而给我们隐藏了具体逻辑。其实在delegate中提供了

一个Target和Method属性,当我们传入bird.Fly时,Target记录了Bird这个类,Method记录了Bird中的Fly方法,所以invoke的时

候会自动触发Bird类中的Fly方法。证据如下:

这里补充一点,当new FlyAction的时候如果是静态方法,那么Target=null的,编译器只需要通过Method就能找到触发的方法。

Q:为什么在多播委托中,不建议回调方法有返回值,即使有返回值,多播中的方法也只能返回最后一个值,如果我想获取每个方法

的返回值,应该怎么处理? 实例代码如下:

1classProgram2{3publicdelegatestringFlyAction();45staticvoidMain(string[] args)6{7Bird bird =newBird();89FlyAction action1 =newFlyAction(bird.Fly);1011FlyAction action2 =newFlyAction(bird.Fly);1213FlyAction action3 =newFlyAction(bird.Fly);1415action1 +=action2;1617action1 +=action3;1819Console.WriteLine(action1.Invoke());2021varresult =action1.GetInvocationList();2223Console.Read();24}25}2627publicclassBird28{29publicstaticRandom rand =newRandom();3031publicstringFly()32{33return"i can fly"+rand.Next();34}35}

A: 既然提到了“多播”,其实就是唬人了,内部源代码里面就是维护了一个List,将“多播”中的方法都放入到List中,Invoke的时候,

就循环遍历下List来依次调用里面的方法,这就是为什么建议不要用“有返回值“的方法。

下面我们可以通过 GetInvocationList 来获取这个list里面的方法。

然后我们再来看看这个GetInvocationList 里面的代码是怎么写的。

看到了this._invocationList和for循环,是不是有一种彻底明白的感觉,如果你想获取每个方法的返回值,那只能通过

GetInvocationList拿出来后,自己手工处理了,只有这样才能拿到“多播委托”中每个方法的返回值。

Q:请问下最后一个问题,问完就睡觉,请问委托可以动态创建吗?

A:可以的。Delegate中提供了CreateDelegate方法,就是可以动态创建的,举个例子你就知道了。

1classProgram2{3publicdelegatestringFlyAction();45staticvoidMain(string[] args)6{7Bird bird =newBird();89//找到类下的方法10varmethod =typeof(Bird).GetMethod("Fly", BindingFlags.Instance |BindingFlags.Public);1112varmydelegate = (FlyAction)Delegate.CreateDelegate(typeof(FlyAction), bird, method);1314varresult =mydelegate.Invoke();15}16}1718publicclassBird19{20publicstringFly()21{22return"i can fly"+newRandom().Next();23}24}

 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
 
© 2005- 王朝網路 版權所有 導航