全网整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:400-708-3566

C# 反射与dynamic最佳组合示例代码

在 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缓存、负载均衡等技术我认为更实际一些。


# c  # dynamic  # 反射  # 详解C# 匿名对象(匿名类型)、var、动态类型 dynamic  # C# dynamic关键字的使用方法  # C#动态对象(dynamic)详解(实现方法和属性的动态)  # C# Dynamic关键字之:dynamic为什么比反射快的详解  # C#使用dynamic类型访问JObject对象  # C#中dynamic关键字的正确用法(推荐)  # 深入浅析C#中的var和dynamic  # c#使用dynamic类型优化反射的方法  # c# dynamic的使用详解  # C#中dynamic动态类型的具体使用  # 加载  # 在此  # 类库  # 请输入  # 请参考  # 运行速度  # 的是  # 也不  # 给我  # 很好  # 会有  # 给你  # 也会  # 你可以  # 就能  # 这就是  # 如有  # 是由  # 你在  # 当你 


相关文章: 在线制作视频网站免费,都有哪些好的动漫网站?  如何在建站之星网店版论坛获取技术支持?  已有域名能否直接搭建网站?  公众号网站制作网页,微信公众号怎么制作?  网站制作软件有哪些,制图软件有哪些?  如何在宝塔面板中创建新站点?  西安专业网站制作公司有哪些,陕西省建行官方网站?  建站主机无法访问?如何排查域名与服务器问题  如何选择香港主机高效搭建外贸独立站?  如何在服务器上配置二级域名建站?  如何通过多用户协作模板快速搭建高效企业网站?  微课制作网站有哪些,微课网怎么进?  C#怎么使用委托和事件 C# delegate与event编程方法  如何零基础开发自助建站系统?完整教程解析  如何高效利用200m空间完成建站?  建站之星导航菜单设置与功能模块配置全攻略  网站制作怎么样才能赚钱,用自己的电脑做服务器架设网站有什么利弊,能赚钱吗?  如何用已有域名快速搭建网站?  再谈Python中的字符串与字符编码(推荐)  浅析上传头像示例及其注意事项  ui设计制作网站有哪些,手机UI设计网址吗?  电视网站制作tvbox接口,云海电视怎样自定义添加电视源?  如何配置IIS站点权限与局域网访问?  如何通过可视化优化提升建站效果?  小建面朝正北,A点实际方位是否存在偏差?  广州网站设计制作一条龙,广州巨网网络科技有限公司是干什么的?  东莞专业网站制作公司有哪些,东莞招聘网站哪个好?  linux top下的 minerd 木马清除方法  如何通过商城免费建站系统源码自定义网站主题?  如何确认建站备案号应放置的具体位置?  C++用Dijkstra(迪杰斯特拉)算法求最短路径  如何选择高效稳定的ISP建站解决方案?  学校建站服务器如何选型才能满足性能需求?  无锡营销型网站制作公司,无锡网选车牌流程?  金*站制作公司有哪些,金华教育集团官网?  企业网站制作费用多少,企业网站空间一般需要多大,费用是多少?  Android自定义listview布局实现上拉加载下拉刷新功能  企业网站制作公司网页,推荐几家专业的天津网站制作公司?  建站VPS选购需注意哪些关键参数?  制作企业网站建设方案,怎样建设一个公司网站?  建站之星代理如何优化在线客服效率?  ,购物网站怎么盈利呢?  如何在云指建站中生成FTP站点?  python的本地网站制作,如何创建本地站点?  洛阳网站制作公司有哪些,洛阳的招聘网站都有哪些?  网站制作软件免费下载安装,有哪些免费下载的软件网站?  深圳网站制作的公司有哪些,dido官方网站?  如何在Golang中使用replace替换模块_指定本地或远程路径  唐山网站制作公司有哪些,唐山找工作哪个网站最靠谱?  昆明高端网站制作公司,昆明公租房申请网上登录入口? 

您的项目需求

*请认真填写需求信息,我们会在24小时内与您取得联系。