在 C# 中反射技术应用广泛,至于什么是反射.........你如果不了解的话,请看下段说明,否则请跳过下段。广告一下:喜欢我文章的朋友请关注一下我的blog,这也有助于提高本人写作的动力。

反射:当你背对一个美女或帅哥却不能回头仔细观察研究时(纯属虚构,如有巧合、纯属雷同),一面小镜子就能满足你的需求。在 C# 编程过程中也经常遇到类似的情况:有一个别人写的 dll 类库你想使用却没程序文档资料......此时通过 C# Runtime 提供的功能,你可以把该 dll 类库加载到你的程序中,并细细研究 dll 的每一部分内容,这就是 C# 中的反射。

个人认为反射最突出的优点或存在的合理性:在不修改程序原码的情况下,实现程序功能的动态调整(Runtime动态对象创建)

示例:

    interface IRun {void Run();}class Person : IRun { public void Run() { Console.WriteLine("走,去LOL啊!"); } } class Car : IRun { public void Run() { Console.WriteLine("呜..........."); } } class Program { static void Main(string[] args) { IRun e = new Person(); e.Run(); Console.ReadLine(); } }

如果将上面的Run功能并不一定是由Person来执行,有时需要是Car有时需要Person。常见的解决方案是添加 if 等判断结构,如下:

       static void Main(string[] args){Console.WriteLine("请输入:Car或Person"); string type = Console.ReadLine(); IRun e = null; if ("Car" == type) { e = new Car(); }else if("Person" == type) { e = new Person(); } if(null != e) e.Run(); Console.ReadLine(); }

这种结构确是解决了现在的需求,但并不健壮。随着 IRun 接口实现、相关类的继承的增加,上面的判断结构也会飞速增长。面向对象编程、设计模式均遵循的一大原则就是封装变换,所以上面的程序无法很好的应对变化。在此我们并不涉及 “设计模式的” 的知识,因此下面的示例代码只为简化上面的程序、并未刻意套用设计模式相关知识。如下:

        static void Main(string[] args){Console.WriteLine("请输入:Car或Person"); string type = Console.ReadLine(); string classPath = String.Format("namespace.{0}", type); IRun e = Activator.CreateInstance(null, classPath).Unwrap() as IRun; if(null != e) e.Run(); Console.ReadLine(); }

经过上面的修改,程序可自行根据用户的输入,通过Activator.CreateInstance创建 IRun 的实例,程序此处不会再随 IRun 的实现者增多这种问题的影响而发生变化。上面的这种优点就是通过反射得到的,也是我所认为的“反射存在的合理性”。

Activator、Assembly 实现反射方式创建对象

C#中反射方式创建对象可以通过 Activator.CreateInstance(静态)和 Assembly.CreateInstance(非静态)来实现,其中Assembly.CreateInstance 内部调用的仍是Activator.CreateInstance。

根据要动态创建的类型对象是否处于当前程序集之中,可将反射创建对象分为:创建程序集内的类型对象与创建程序集外的类型对象。

创建程序集内的类型对象

        private static void ReflectionIRun1(string className){string classPath = String.Format("namespace.{0}", className); //参数 null ,指出所要创建类型对象位于当前程序集 var handler = Activator.CreateInstance(null, classPath); IRun e = (IRun)handler.Unwrap(); Console.WriteLine(e.Run()); } private static void ReflectionIRun2(string className) { string classPath = String.Format("namespace.{0}", className); //typeof(IRun).Assembly 获取 IRun 类型所在的程序集 object obj = typeof(IRun).Assembly.CreateInstance(null, classPath); IRun e = (IRun)obj; Console.WriteLine(e.Run()); }

创建程序集外的类型对象

项目中增加一个 类库 (另一个程序集),如下图:

添加一个 Boss 类,如下:

namespace Lib
{public class Boss{private string name = "老大"; public string Name{ get {return name;} } public string Talk() { return "你们都被开除了......"; } //老板不会算账,总是多付钱,所以很有自知之明的将Payfor设为private,防止外部人员调用 private int Payfor(int total) { return total + 10; } } } 

获取 一个 Boss 对象前,首先添加对 Lib 的引用,获取示例如下:

        private static void ReflectionBoss1(){string classPath ="Lib.Boss"; //"Lib" 参数指明要加载的程序集(即要创建的对象类型在哪个程序集中定义) var handler = Activator.CreateInstance("Lib", classPath); Boss b = handler.Unwrap() as Boss; Console.WriteLine(b.Talk()); } private static void ReflectionBoss2() { string classPath ="Lib.Boss"; //Assembly.Load("Lib") 加载的程序集(即要创建的对象类型在哪个程序集中定义) var assembly = Assembly.Load("Lib"); Boss b = (Boss)assembly.CreateInstance(classPath); Console.WriteLine(b.Talk()); } 

关于反射时CLR如何查找并定位要加载的程序集,请参考MSDN中关于反射相关的知识。

反射访问字段、调用方法(属性

反射除可以帮我们动态创建对象外,还可帮我们动态访问对象的方法(属性)或字段,因 C# 版本不同具体方法会有变更或扩展,更深入内容请参考MSDN。下面仅作简单示例(标准用法)。

给老板改名,示例:

        private static void ReflectionBoss1(){string classPath = "Lib.Boss"; //"Lib" 参数指明要加载的程序集(即要创建的对象类型在哪个程序集中定义) var handler = Activator.CreateInstance("Lib", classPath); Boss b = handler.Unwrap() as Boss; //关键代码 FieldInfo f = b.GetType().GetField("name", BindingFlags.GetField | BindingFlags.NonPublic | BindingFlags.Instance); f.SetValue(b, "小二"); Console.WriteLine("{0}:{1}", b.Name, b.Talk()); }

输出:

让老板付钱:

private static void ReflectionBoss1(){string classPath = "Lib.Boss"; //"Lib" 参数指明要加载的程序集(即要创建的对象类型在哪个程序集中定义) var handler = Activator.CreateInstance("Lib", classPath); Boss b = handler.Unwrap() as Boss; //关键代码 MethodInfo method = b.GetType().GetMethod("Payfor", BindingFlags.InvokeMethod | BindingFlags.NonPublic | BindingFlags.Instance); object money = method.Invoke(b, new object[] { 10 }); Console.WriteLine("DW039:老大给我报销10元钱车费......"); Console.WriteLine("{0}:.....,算不清了,给你这些吧。",b.Name); Console.WriteLine("DW039:......"); Console.WriteLine("{0}:{1}", b.Name,money); Console.WriteLine("DW039:老大你真棒!"); }

输出:

dynamic 与 反射 双剑合璧

因为反射是运行时的类型操作,所以在编程时面临类型不确定的问题。根据上一篇《C# 匿名对象(匿名类型)、var、动态类型 dynamic》讲得 dynamic 动态类型结合我们编写的反射程序,可以大大优化程序逻辑(访问受保护级别限制的代码不在此范围内)。

上面代码的优化:

 private static void ReflectionBoss1(){string classPath ="Lib.Boss"; var handler = Activator.CreateInstance("Lib", classPath); dynamic b = handler.Unwrap(); Console.WriteLine(b.Talk()); } private static void ReflectionBoss2() { string classPath ="Lib.Boss"; var assembly = Assembly.Load("Lib"); dynamic b = assembly.CreateInstance(classPath); Console.WriteLine(b.Talk()); } 

通过 dynamic 动态类型对象 b 来调用反射得到对象的属性、方法可直接调用,从而省去了频繁的类型转换操作。

反射常见应用场景

应用场景我印象最深刻的是 MS Petshop 示例,从SQL Server 数据库切换到 oracle 数据库时反射获得不同的数据访问层。然我实际项目中从未遇到过中途切换数据库的情况,其他应用场景基本类似上面的示例。如果朋友你发现更多的应用场景,请给予补充,3ks。

反射的优缺点

优点:反射使程序更灵活

缺点:反射运行速度相对较慢

至于反射相比普通程序慢,我没有进行过测试也不打算进行。现实情况是:Ms提倡使用 dynamic、Mvc流行、Ms对CLR不断优化、机器性能的提升,所以你在开发中无需过多考虑反射的性能问题。如果你写的程序运行速度出现了瓶颈(应首先确保自己程序写的合理),研究一下数据库优化、数据缓存、web缓存、负载均衡等技术我认为更实际一些。

转载于:https://www.cnblogs.com/MuNet/p/8545989.html

C# 反射与dynamic最佳组合相关推荐

  1. 虚拟桌面最佳组合---Windows 7

    从去年开始虚拟桌面开始在国内遍地开花时,其实,用户一直在观望,像是观望楼市一样观望,都在等最好虚拟桌面产品(XenDesktop\View\Microsoft VDI),以及最优的虚拟桌面组合.其实, ...

  2. 工厂电子产品工艺文件_建智能工厂,人机如何达到最佳组合?

    导 读 ( 文/ e-works CEO 黄培博士 ) 在推进智能工厂建设的过程中,如何根据制造企业的产品特点和生产模式来确定工人与机器的最佳组合,是个至关重要的问题. 企业既不能盲目地推进自动化.机 ...

  3. 短线技术指标最佳组合_如何为您选择最佳的技术职业道路

    短线技术指标最佳组合 by Colin Smith 通过科林·史密斯 如何为您选择最佳的技术职业道路 (How to choose the best tech career path for you) ...

  4. java反射之dynamic invocation与原生类型

    java反射之dynamic invocation与原生类型 java中的方法参数或者返回值可能为原生类型,反射调用方法的时候,理解在反射invoke方法中如何使用原生类型很重要.        如果 ...

  5. 找零钱最佳组合的测试用例

    文章目录 找零钱最佳组合的测试用例 一.分析输入的情形 二. 分 析 输 出 情 形 三. 具体情形分析 四,测试用例: 五,等价类划分 找零钱最佳组合的测试用例 假设商店货品价格®皆不大於100元( ...

  6. 【等价类划分法】某商店的货品价格(P)都不大于 20 元(且为整数),假设顾客每次付款为 20 元且每次限购一件商品,现有一个软件能在每位顾客购物后给出找零钱的最佳组合(找给顾客货币张数最少)。

    题目: [说明] 某商店的货品价格(P)都不大于 20 元(且为整数),假设顾客每次付款为 20 元且每次限购一件商品,现有一个软件能在每位顾客购物后给出找零钱的最佳组合(找给顾客货币张数最少). 假 ...

  7. 钱包软件测试,软件测试找零钱最佳组合的测试用例.doc

    PAGE / NUMPAGES 找零钱最佳组合的测试用例 假设商店货品价格(R)皆不大於100元(且为整数),若顾客付款在100元内(P),求找给顾客之最少货币个(张)数?(货币面值50元(N50), ...

  8. 找零钱最佳组合,实验报告(请结合等价类划分法和边界值分析法为上述程序设计出相应的测试用例)

    实验:找零钱最佳组合,实验报告 一.实验目的: (1)掌握黑盒测试的等价类划分和边界值划分的基本方法 (2)利用等价类划分和边界值分析的方法,正确的设计测试用例 实验重点及难点: 重点:正确地划分等价 ...

  9. python windows窗口开发_Windows 平台做 Python 开发的最佳组合

    选自机器之心 作者:Jon Fincher 在 Windows 上怎样做 Python 开发?是像大神那样使用纯文本编辑器,还是用更加完善的 IDE?到底是用自带的命令行工具,还是需要装新的 Term ...

最新文章

  1. 分类评分函数 score function
  2. 【译】Ethereum Wallet in a Trusted Execution Environment / Secure Enclave
  3. webpack打包之clean-webpack-plugin插件 默认下载4.0.0版本的踩坑记录
  4. 如何使用新的邮件传输规则和邮件策略
  5. python音频聚类_python实现鸢尾花三种聚类算法(K-means,AGNES,DBScan)
  6. NPM 修复两个严重漏洞但无法确认是否已遭在野利用,可触发开源软件供应链攻击...
  7. web服务器ngix基础
  8. Pytorch入门教程学习笔记(六)循环神经网络RNN(学周杰伦写歌)
  9. 解决SQL适配器连接到字符集为US7ASCII的Oracle数据库的中文乱码问题
  10. C语言中Strcpy 的使用
  11. du 查看文件大小命令
  12. c语言功率算电量,电功率你理解透了吗?怎么算功率因数?1度电是多少?
  13. J - Virus UVA - 12511——最长上升递增子序列
  14. 深圳弘辽科技电商:拼多多“砍单免费拿”:一场关于人性的较量
  15. 你是那种只看《XXXXX从入门到精通》的程序员吗?
  16. 乐视三合一体感摄像头(Orbbec Astra Pro)在ROS下安装使用
  17. vivado实现SDI接口
  18. 协程的概念,为什么要用协程,以及协程的使用
  19. 中级前端面试秘籍(含详细答案,15k级别)
  20. 理想与现实:HI3516编译Valgrind

热门文章

  1. [译]学习IPython进行交互式计算和数据可视化(四)
  2. spring web参数传递
  3. 重装win8系统后变成C盘了别的分区的资料怎样恢复
  4. 聊聊webflux参数校验
  5. 基于intellij和meavn的整合开发struts2框架的web程序
  6. ming 贪心 NOIP模拟
  7. 关于Oracle full outer join 的bug问题分析及处理
  8. poj 2763 Housewife Wind
  9. 判断图有无环_萧阳环保教你判断布袋除尘器是否合格记住这3点
  10. python机械臂仿真_VTK与Python实现机械臂三维模型可视化详解