再议C#方法中的反射方式和委托方式

我们将要谈到的是C#方法中的反射方式和委托方式,文中还将给出具体代码,以方便大家测试和实践。

AD:

在开发过程中对静态方法的调用是通过类型名后面加个点而后是调用方法的名称,对类型实例方法的调用是通过new一个对象,而后点加方法名称,这是最熟悉不过的两种方式。还可以通过读取CLR元数据,利用反射进行方法调用。在利用反射方式调用方法时,最重要的两个类是System.Type和System.Reflection.MethodInfo。用MethodInfo类型的Invoke方法调用方法,必须传入目标对象实例的引用。如下:

  1. public class Calculate
  2. {
  3. //使用反射可以调用私有方法
  4. private intAdd(int leftNum, int rightNum)
  5. {
  6. return leftNum + rightNum;
  7. }
  8.  }
  9. classProgram
  10. {
  11. static voidMain(string[] args)
  12. {
  13. //用type.getmethod的方法获取类型方法,BindingFlags设置查找方法的范围
  14. //本例是公有方法,私有方法而且是非静态的才被查找,如果要查找静态方法
  15. //需要设置BindingFlags.Static
  16. MethodInfo method = typeof(Calculate).GetMethod("Add", BindingFlags.Public
  17. | BindingFlags.NonPublic
  18. |BindingFlags.Instance);
  19. if(method == nullreturn
  20. //调用方法的参数
  21. object[] paras ={ 10, 20 };
  22. //目标对象实例:new Calculate()
  23. objectresult = method.Invoke(new Calculate(), paras);
  24. Console.WriteLine(result);
  25. Console.ReadLine();
  26. }
  27. }

委托方式

任何对象都可以调用委托,只要方法返回值以及方法签名和委托声明一样就行。

通过阅读CLR源代码,整理了委托类的重要字段和几个常用方法,自定义的委托类型都派生于MulticastDelegate。

  1. public abstract class Delegate: ICloneable,ISerializable
  2. {
  3. // 调用目标对象,实例方法为类型实例引用,静态方法则为null
  4. internalObject_target;
  5. //指向调用方法
  6. internalIntPtr_methodPtr;
  7. //委托构造器
  8. protected Delegate(Objecttarget, Stringmethod)
  9. {
  10. //省略,具体看以查看clr源代码
  11. }
  12. public static Delegate CreateDelegate(Typetype, Objecttarget, Stringmethod)
  13. {
  14. //省略,具体看以查看clr源代码
  15. }
  16. public static Delegate CreateDelegate(Typetype, Typetarget, Stringmethod)
  17. {
  18. //省略,具体看以查看clr源代码
  19. }
  20. public static Delegate Combine(paramsDelegate[] delegates) {}
  21. public static Delegate Combine(Delegatea, Delegateb) {}
  22. public static Delegate Remove(Delegatesource, Delegatevalue){}
  23. }
  24. public abstract class MulticastDelegate: Delegate
  25. {
  26. private Object _invocationList;
  27. protected MulticastDelegate(Objecttarget, Stringmethod) : base(target, method) { }
  28. protectedMulticastDelegate(Typetarget, Stringmethod): base(target, method) { }
  29. }

从源代码可以看出Delegate类提供了几个重载的静态方法CreateDelegate,方法返回值是Delegate类型。如果是实例方法则把对象引用传递给它,如是静态方法则传入对象类型。

  1. publicdelegateintDelegateCaculate(inta,intb);
  2. publicclassCaculate
  3. {
  4. publicintAdd(intnum1, intnum2)
  5. {
  6. returnnum1 + num2;
  7. }
  8. publicstaticintSubtract(intnum1, intnum2)
  9. {
  10.  returnnum2 - num1;
  11. }
  12. }
  13. classProgram
  14.  {
  15. staticvoidMain(string[] args)
  16. {
  17. Caculatecaculate = newCaculate();
  18. TypetypeCaculate = typeof(Caculate);
  19. TypetypeDelegate = typeof(DelegateCaculate);
  20. DelegateCaculateadd = (DelegateCaculate)Delegate.CreateDelegate(typeDelegate, caculate, "Add");
  21. DelegateCaculatesubtract = (DelegateCaculate)Delegate.CreateDelegate(typeDelegate, typeCaculate, "Subtract");
  22. Console.WriteLine("add:"+ add(10, 20));
  23. Console.WriteLine("subtract:"+ subtract(10, 20));
  24. Console.ReadLine();
  25. }
  26. }

CreateDelegate需要通过遍历元数据来获取方法句柄。C#语法提供了更便利的方法来调用委托,可以简单通过类型名或者对象名来限定方法,而且不需要通过遍历元数据,C#编译器使用底层CIL的ldftn或许ldvirtftn操作符获取方法地址,相对来说要比CreateDelegate快的多了。上面的Main方法可以改写为

  1. staticvoidMain(string[] args)
  2. {
  3. DelegateCaculateadd = newDelegateCaculate(newCaculate().Add);
  4. DelegateCaculatesubtract = newDelegateCaculate(Caculate.Subtract);
  5. Console.WriteLine("add:"+ add(10, 20));
  6. Console.WriteLine("subtract:"+ subtract(10, 20));
  7. Console.ReadLine();
  8. }

可以将多个委托对象放到委托对象数组中,一旦对其调用,CLR将遍历委托数组,对其逐一调用。

  1. publicdelegatevoidDelegateCaculate(inta,intb);
  2. publicclassCaculate
  3. {
  4. publicstaticvoidAdd(intnum1, intnum2)
  5. {
  6. Console.WriteLine((num1+ num2));
  7. }
  8. publicstaticvoidSubtract(intnum1, intnum2)
  9. {
  10. Console.WriteLine((num2- num1));
  11. }
  12. }
  13. classProgram
  14. {
  15. staticvoidMain(string[] args)
  16. {
  17. DelegateArray(newDelegateCaculate(Caculate.Add), newDelegateCaculate(Caculate.Subtract));
  18. Console.ReadLine();
  19. }
  20. staticvoidDelegateArray(DelegateCaculatea, DelegateCaculateb)
  21. {
  22. DelegateCaculatedelChain = null
  23. delChain = (DelegateCaculate)Delegate.Combine(delChain, a);
  24. delChain = (DelegateCaculate)Delegate.Combine(delChain, b);
  25. delChain(10, 20);
  26. }
  27. }

C#提供了更便捷的语法把委托对象添加到委托数组内,可以这样修改上面的DelegateArray方法,

  1. staticvoidDelegateArray(DelegateCaculatea, DelegateCaculateb)
  2.  {
  3. DelegateCaculatedelChain = null
  4. delChain += a;
  5. delChain+=b;
  6. delChain(10, 20);
  7. }

当执行(DelegateCaculate)Delegate.Combine(delChain, a)时,因为委托数组中只有一个a对象,所以delChain也只是简单的指向a。示意图如下

当执行(DelegateCaculate)Delegate.Combine(delChain, b)是,因为委托数组已经有两个对象了,这时会生成一个新的MulticastDelegate对象让delChain指向它,而_invocationList指向一个委托数组对象,示意图如下

如果还有委托对象加入,将会再次生成一个新的MulticastDelegate对象让delChain指向这个新对象,原来的对象则等待垃圾回收器进行回收,这点可以查看CLR源代码,每添加一个委托对象就调用一次方法NewMulticastDelegate,这个方法返回值是MulticastDelegate。

委托与接口

接口与委托都拥有调用特定方法的能力,所以他们在这点很相像。但是接口需要目标方法的类型声明必须与该接口兼容,而委托可以被任何类型调用,只要该类型的目标方法签名和委托签名匹配即可。

那么何时用委托,何时用接口呢,msdn 总结的非常好,我就直接给粘贴过来了,

委托在以下情况很有用:

1、 调用单个方法。

2、 一个类希望有方法规范的多个实现。

3、 希望允许静态方法实现规范。

4、 希望类似事件的设计模式。

5、 调用方不需要知道或获得实现与委托签名匹配的方法的对象。

6、 实现的提供程序希望只对少数选择组件“分发”规范实现。

7、 需要方法的组合。

接口在以下情况很有用:

1、 规范定义一组相关方法。

2、 类通常只实现规范一次。

3、 接口的调用方希望转换为接口类型或从接口类型转换,以获得其他接口或类。

原文链接:http://www.cnblogs.com/qiuwuyu/archive/2011/08/29/2157230.html

本文转自左正博客园博客,原文链接:http://www.cnblogs.com/soundcode/archive/2011/10/14/2211409.html,如需转载请自行联系原作者

再议C#方法中的反射方式和委托方式相关推荐

  1. C#方法中的反射方式和委托方式(小实例)

    在开发过程中对静态方法的调用是通过类型名后面加个点而后是调用方法的名称,对类型实例方法的调用是通过new一个对象,而后点加方法名称,这是最熟悉不过的两种方式.还可以通过读取CLR元数据,利用反射进行方 ...

  2. ztree在onCheck()方法中防止因触发联动关系导致页面多次渲染而卡死的问题

    这几天在项目中遇到了要使用树形选择框, 而且要求比较复杂,具体叙述如下: 首先是有个选择框,左边选择是适用的商品,右边显示已经选择的商品.也就是说,左边每次勾选操作,都要触发一个事件去刷新右边的页面, ...

  3. 《智源社区周刊:预训练模型》第2期:Facebook用“预微调”改进预训练性能、再议GPT-3中的东方主义偏见...

    超大规模预训练模型是当前人工智能领域研究的热点,为了帮助研究与工程人员了解这一领域的进展和资讯,智源社区整理了第2期<智源社区周刊:预训练模型>,从论文推荐.研究动态.热点讨论等几个维度推 ...

  4. java中的static类_再议Java中的static关键字

    再议Java中的static关键字 java中的static关键字在很久之前的一篇博文中已经讲到过了,感兴趣的朋友可以参考:<Java中的static关键字解析>. 今天我们再来谈一谈st ...

  5. 深入理解Java中的反射机制和使用原理!详细解析invoke方法的执行和使用

    反射的概念 反射:Refelection,反射是Java的特征之一,允许运行中的Java程序获取自身信息,并可以操作类或者对象的内部属性 通过反射,可以在运行时获得程序或者程序中的每一个类型的成员活成 ...

  6. Java 中使用反射来创建对象、调用方法

    Java 中使用反射来创建对象.调用方法 反射创建对象 反射调用方法 反射调用私有方法 反射调用可变参私有方法 反射调用的方法自身可以抛出异常的情形   假设已有下面的类: import java.l ...

  7. 枚举转中文,通过反射方法与描述的方式获取

    示例: 有人为了显示中文,这样定义枚举吗? publicenum TimeOfDay { 上午, 下午, 晚上 }; 这样定义,很别扭,特别是在使用的时候, 比如,this.Time = TimeOf ...

  8. php 反射类 解析注释,php反射获取类和方法中的注释

    通过php中的反射机制,获取该类的文档注释,再通过获取其所有的方法,获取方法的注释 所用到的主要类及其方法 ReflectionClass ReflectionClass::getDocComment ...

  9. java 反射 main_java – 通过反射访问main方法中的局部变量

    Since main is static, is it possible to access instanceOfB in order to access the value of _nonStati ...

最新文章

  1. Xamarin XAML语言教程基本页面ContentPage占用面积内容页面的派生关系与属性
  2. Linux 软件看门狗 watchdog
  3. nginx负载均衡策略upstream
  4. 2000坐标系高程与85高程转换_科普 | 如何在大疆智图中设置坐标系
  5. java我的世界1.7.2怎么下载模组_我的世界1.7.2
  6. PyQt5 技术篇-设置窗口启用默认桌面位置,按屏幕比例
  7. app启动页数秒加载 代码_iOS 底层探索 - 应用加载
  8. Predicate接口练习之筛选满足条件数据
  9. TensorFlow 官方文档中文版
  10. Windows.etc\hosts文件
  11. Java读取Excel文件
  12. 程序包管理器控制台 Add-Migration 用法
  13. 瑞幸咖啡股价再大涨超36% 目前总市值约13.87亿美元
  14. 换手机的再等等!iPhone SE2还有戏:苹果官网悄然更新AppleCare+服务计划
  15. LVS-NAT工作模式的实现
  16. html中什么是围堵标签,HTML回顾(基础标签)
  17. JMX实现远程服务器Tomcat系统监控之三
  18. 北京市通州区谷歌卫星地图下载
  19. SM2258XT数据恢复全解,慧荣SM2258XT主控数据恢复详细教程,SM2259XT可参考
  20. 小学期助教感受-Funcode游戏编程

热门文章

  1. Python 回溯算法
  2. 第五篇:JMeter 定时器
  3. System.arraycopy(src, srcPos, dest, destPos, length) 与 Arrays.copyOf(original, newLength)区别
  4. python的os模块批量获取目标路径下的文件名
  5. Sql结果导出为excel文件
  6. PDF.NET数据开发框架操作MySQL实体类操作实例
  7. 【转】学习asp.net比较完整的流程
  8. 详细程序注解学OpenCL一 环境配置和入门程序
  9. 计算机视觉目标检测的框架与过程
  10. MarkdownPad2基础语法