C#反射的Assembly的简单应用

  反射(Reflection)是.NET中的重要机制,经过反射,能够在运行时得到.NET中每个类型(包括类、结构、委托、接口和枚举等)的成员,包括方法、属性、事件,以及构造函数等。还能够得到每一个成员的名称、限定符和参数等。有了反射,便可对每个类型了如指掌。若是得到了构造函数的信息,便可直接建立对象,即便这个对象的类型在编译时还不知道。

Assembly就是反应反射的一种应用,它定义和加载程序集,加载在程序集清单中列出模块,以及今后程序集中查找类型并建立该类型的实例。简单地说就是,使用Assembly在程序中你不用事先写好比下面的东西了:html

PersonClass person = new PersonClass();  person.Method();

 你只要知道PersonClass这个类的程序集,命名空间和类名直接使用反射就可使用。你只须要这样写:ide

PersonClass person;  person =   person = (PersonClass)(Assembly.Load("程序集").CreateInstance("命名空间.类名", false, BindingFlags.Default, null, args, null, null));  person.Method();

下面用一个小例子来看看Assembly应用的方便性。函数

需求:有几种文件格式,后缀分别是.One,.Two,.Three,... 有不少种,后续还可能增长。这些文件的格式都不同,也就是说读取方式就不同。那么根据传入的文件后缀和路径读出文件的内容。性能

实现:spa

这种需求的特色是,根据选择作不一样的处理,可是都是出的一种结果,那么可使用简单工厂模式来完成。code

读取文件有一个父类FileSuper,内部以下:xml

using System;  using System.Collections.Generic;  using System.Text;    namespace reflect  {      public abstract class FileSuper//获取不一样后缀名文件的内容      {         public abstract string GetFileContext(string fileFullPath);      }  }

分别有MyFileOne,MyFileTwo,MyFileThree等,继承FileSuper,以下:htm

using System;  using System.Collections.Generic;  using System.Text;    namespace reflect  {      public class MyFileOne : FileSuper      {          public override string GetFileContext(string fileFullPath)          {              return "One类型文件的内容";          }      }  }
using System;  using System.Collections.Generic;  using System.Text;    namespace reflect  {      public class MyFileTwo : FileSuper      {          public override string GetFileContext(string fileFullPath)          {              return "Two类型文件的内容";          }      }  }  
using System;  using System.Collections.Generic;  using System.Text;    namespace reflect  {      public class MyFileThree : FileSuper      {          public override string GetFileContext(string fileFullPath)          {              return "Three类型文件的内容";          }      }  }  

一个工厂类根据后缀名决定实例化哪一个类:对象

using System;  using System.Collections.Generic;  using System.Text;    namespace reflect  {      public class OperationFile      {          static FileSuper fileSuper = null;            public static string GetStringByFile(string fileFullPath, string extendName)          {              switch (extendName)              {                  case "One":                        fileSuper = new MyFileOne();                        break;                    case "Two":                        fileSuper = new MyFileTwo();                        break;                    case "Three":                        fileSuper = new MyFileThree();                        break;              }                if (fileSuper != null)              {                  return fileSuper.GetFileContext(fileFullPath);              }                return "没有指定的类型";          }      }  }

客户端调用,显示结果:继承

using System;  using System.Collections.Generic;  using System.Text;    namespace reflect  {      public class Program      {          static void Main(string[] args)          {              string fileContext = OperationFile.GetStringByFile("路径", "One");                Console.WriteLine(fileContext);                Console.ReadLine();          }      }  }

这样解决了这个需求,前面在读书笔记6:工厂方法模式 中提到了这种方式的缺点,就是不符合开放封闭原则,那么如何改进了,除了工厂方法模式,咱们可使用Assembly。使用它以前,要先写一个类和一个配置文件。

先看配置文件:MyFile.xml

<?xml version="1.0" encoding="utf-8" ?>  <FileExtendName>    <extend>      <name>One</name>      <class>MyFileOne</class>    </extend>    <extend>      <name>Two</name>      <class>MyFileTwo</class>    </extend>    <extend>      <name>Three</name>      <class>MyFileThree</class>    </extend>  </FileExtendName>

是后缀名和类名的对应。

另外一个读取配置文件的类ExtendNameDataTable。

using System;  using System.Collections.Generic;  using System.Text;  using System.Data;    namespace reflect  {      public class ExtendNameDataTable      {          private static DataSet extendDataSet;            public static DataSet ExtendDataSet          {              get              {                  if (extendDataSet == null)                  {                      extendDataSet = new DataSet();                        extendDataSet.ReadXml(@"F:\MyFile.xml");                  }                  return extendDataSet;              }          }      }  }

作好这两个准备后,只需修改OperationFile工厂类,其他都不用修改。使用Assembly来根据配置文件,自动按照传入的后缀名加载类,而且实例化,修改后的OperationFile以下:

using System;  using System.Collections.Generic;  using System.Text;  using System.Data;  using System.Reflection;    namespace reflect  {      public class OperationFile      {            public static string GetStringByFile(string fileFullPath, string extendName)          {                DataRow dr = ((DataRow[])ExtendNameDataTable.ExtendDataSet.Tables[0].Select("name='" + extendName + "'"))[0];                object[] args = null;                FileSuper fileSuper;                fileSuper = (FileSuper)(Assembly.Load("reflect").CreateInstance(                    "reflect." + dr["class"].ToString(), false, BindingFlags.Default, null, args, null, null));                return fileSuper.GetFileContext(fileFullPath);            }      }  }

客户端调用不变输出结果:

咱们看到,这样一来,若是有了新的文件结构,只须要再写一个MyFileFour类继承自FileSuper;而后再在MyFile.xml中增长相应的对应关系就能够了,避免了要修改OperationFile的case分支,符合开放封闭原则。

    固然Assembly这么好使用,也不是全部状况下都能用的,当在循环中碰到了这种状况,那么仍是使用简单工厂模式或者工厂方法模式吧,由于再循环中使用Assembly实例化会致使性能降低。

相关文章
相关标签/搜索