旗下导航:搜·么
当前位置:网站首页 > .Net教程 > 正文

C#中关于反射和dynamic最好组合的示例分享【C#.Net教程】,dynamic,csharp,.net

作者:搜教程发布时间:2019-11-27分类:.Net教程浏览:31评论:0


导读:这篇文章重要引见了C#反射与dynamic最好组合示例代码,须要的朋侪能够参考下在C#中反射手艺运用普遍,至于什么是反射.........你假如不相识的话,请看下段申...
这篇文章重要引见了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最好组合的示例分享的细致内容,更多请关注ki4网别的相干文章!

标签:dynamiccsharp.net


欢迎 发表评论: