C#反射的Assembly的简单应用

来源:互联网 发布:维修基金算法 编辑:程序博客网 时间:2024/05/13 10:58
 反射(Reflection)是.NET中的重要机制,通过反射,可以在运行时获得.NET中每一个类型(包括类、结构、委托、接口和枚举等)的成员,包括方法、属性、事件,以及构造函数等。还可以获得每个成员的名称、限定符和参数等。有了反射,即可对每一个类型了如指掌。如果获得了构造函数的信息,即可直接创建对象,即使这个对象的类型在编译时还不知道。

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

[csharp] view plain copy
 print?
  1. PersonClass person = new PersonClass();  
  2. person.Method();  

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

[html] view plain copy
 print?
  1. PersonClass person;  
  2. person =   
  3. person = (PersonClass)(Assembly.Load("程序集").CreateInstance("命名空间.类名", false, BindingFlags.Default, null, args, null, null));  
  4. person.Method();  

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

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

实现:

这种需求的特点是,根据选择做不同的处理,但是都是出的一种结果,那么可以使用简单工厂模式来完成。

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

[csharp] view plain copy
 print?
  1. using System;  
  2. using System.Collections.Generic;  
  3. using System.Text;  
  4.   
  5. namespace reflect  
  6. {  
  7.     public abstract class FileSuper//获取不同后缀名文件的内容  
  8.     {  
  9.        public abstract string GetFileContext(string fileFullPath);  
  10.     }  
  11. }  

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

[csharp] view plain copy
 print?
  1. using System;  
  2. using System.Collections.Generic;  
  3. using System.Text;  
  4.   
  5. namespace reflect  
  6. {  
  7.     public class MyFileOne : FileSuper  
  8.     {  
  9.         public override string GetFileContext(string fileFullPath)  
  10.         {  
  11.             return "One类型文件的内容";  
  12.         }  
  13.     }  
  14. }  
[csharp] view plain copy
 print?
  1. using System;  
  2. using System.Collections.Generic;  
  3. using System.Text;  
  4.   
  5. namespace reflect  
  6. {  
  7.     public class MyFileTwo : FileSuper  
  8.     {  
  9.         public override string GetFileContext(string fileFullPath)  
  10.         {  
  11.             return "Two类型文件的内容";  
  12.         }  
  13.     }  
  14. }  
[csharp] view plain copy
 print?
  1. using System;  
  2. using System.Collections.Generic;  
  3. using System.Text;  
  4.   
  5. namespace reflect  
  6. {  
  7.     public class MyFileThree : FileSuper  
  8.     {  
  9.         public override string GetFileContext(string fileFullPath)  
  10.         {  
  11.             return "Three类型文件的内容";  
  12.         }  
  13.     }  
  14. }  

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

[csharp] view plain copy
 print?
  1. using System;  
  2. using System.Collections.Generic;  
  3. using System.Text;  
  4.   
  5. namespace reflect  
  6. {  
  7.     public class OperationFile  
  8.     {  
  9.         static FileSuper fileSuper = null;  
  10.   
  11.         public static string GetStringByFile(string fileFullPath, string extendName)  
  12.         {  
  13.             switch (extendName)  
  14.             {  
  15.                 case "One":  
  16.   
  17.                     fileSuper = new MyFileOne();  
  18.   
  19.                     break;  
  20.   
  21.                 case "Two":  
  22.   
  23.                     fileSuper = new MyFileTwo();  
  24.   
  25.                     break;  
  26.   
  27.                 case "Three":  
  28.   
  29.                     fileSuper = new MyFileThree();  
  30.   
  31.                     break;  
  32.             }  
  33.   
  34.             if (fileSuper != null)  
  35.             {  
  36.                 return fileSuper.GetFileContext(fileFullPath);  
  37.             }  
  38.   
  39.             return "没有指定的类型";  
  40.         }  
  41.     }  
  42. }  

客户端调用,显示结果:

[csharp] view plain copy
 print?
  1. using System;  
  2. using System.Collections.Generic;  
  3. using System.Text;  
  4.   
  5. namespace reflect  
  6. {  
  7.     public class Program  
  8.     {  
  9.         static void Main(string[] args)  
  10.         {  
  11.             string fileContext = OperationFile.GetStringByFile("路径""One");  
  12.   
  13.             Console.WriteLine(fileContext);  
  14.   
  15.             Console.ReadLine();  
  16.         }  
  17.     }  
  18. }  

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

先看配置文件:MyFile.xml

[html] view plain copy
 print?
  1. <?xml version="1.0" encoding="utf-8" ?>  
  2. <FileExtendName>  
  3.   <extend>  
  4.     <name>One</name>  
  5.     <class>MyFileOne</class>  
  6.   </extend>  
  7.   <extend>  
  8.     <name>Two</name>  
  9.     <class>MyFileTwo</class>  
  10.   </extend>  
  11.   <extend>  
  12.     <name>Three</name>  
  13.     <class>MyFileThree</class>  
  14.   </extend>  
  15. </FileExtendName>  

是后缀名和类名的对应。

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

[csharp] view plain copy
 print?
  1. using System;  
  2. using System.Collections.Generic;  
  3. using System.Text;  
  4. using System.Data;  
  5.   
  6. namespace reflect  
  7. {  
  8.     public class ExtendNameDataTable  
  9.     {  
  10.         private static DataSet extendDataSet;  
  11.   
  12.         public static DataSet ExtendDataSet  
  13.         {  
  14.             get  
  15.             {  
  16.                 if (extendDataSet == null)  
  17.                 {  
  18.                     extendDataSet = new DataSet();  
  19.   
  20.                     extendDataSet.ReadXml(@"F:\MyFile.xml");  
  21.                 }  
  22.                 return extendDataSet;  
  23.             }  
  24.         }  
  25.     }  
  26. }  

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

[csharp] view plain copy
 print?
  1. using System;  
  2. using System.Collections.Generic;  
  3. using System.Text;  
  4. using System.Data;  
  5. using System.Reflection;  
  6.   
  7. namespace reflect  
  8. {  
  9.     public class OperationFile  
  10.     {  
  11.   
  12.         public static string GetStringByFile(string fileFullPath, string extendName)  
  13.         {  
  14.   
  15.             DataRow dr = ((DataRow[])ExtendNameDataTable.ExtendDataSet.Tables[0].Select("name='" + extendName + "'"))[0];  
  16.   
  17.             object[] args = null;  
  18.   
  19.             FileSuper fileSuper;  
  20.   
  21.             fileSuper = (FileSuper)(Assembly.Load("reflect").CreateInstance(  
  22.   
  23.                 "reflect." + dr["class"].ToString(), false, BindingFlags.Default, null, args, nullnull));  
  24.   
  25.             return fileSuper.GetFileContext(fileFullPath);  
  26.   
  27.         }  
  28.     }  
  29. }  

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

我们看到,这样一来,如果有了新的文件结构,只需要再写一个MyFileFour类继承自FileSuper;然后再在MyFile.xml中增加相应的对应关系就可以了,避免了要修改OperationFile的case分支,符合开放封闭原则。

    当然Assembly这么好使用,也不是所有情况下都能用的,当在循环中碰到了这种情况,那么还是使用简单工厂模式或者工厂方法模式吧,因为再循环中使用Assembly实例化会导致性能下降。

0 0