C#学习之反射
反射是.NET中的重要机制,通过反射,可以在运行时获得程序或程序集中每一个类型(包括类、结构、委托、接口和枚举等)的成员和成员的信息。简单来讲,反射的重要用途为:能够调用dll文件中的方法,这样带来的好处是可能在不改变软件总体架构的情况下升级插件。
反射用到的类
反射用到的类有:
1. System.Type 类
2. System.Reflection.Assembly 类
1. System.Type 类
Type 是许多反射功能的入口,它实现许多方法和属性,通过这个类可以访问任何给定数据类型的信息。通常有三种方法获取指向给定类型的Type引用:
//方法1 Typet = typeof(double); //方法2 double d =10; Type t = d.GetType(); //方法3 Type t = Type.GetType("System.Double");
注意:Type可用的属性都是只读的,可以使用Type确定数据的类型,但不能使用它修改该类型!
1.Type的属性
| 属性 |
返回值 |
| Name |
数据类型名 |
| FullName |
数据类型的完全限定名(包括名称空间名) |
| Namespace |
在其中定义数据类型的名称空间名 |
属性还可以进一步获取Type对象的引用,这些引用表示相关的类
| 属性 | 返回对应的Type引用 |
| BaseType | 该Type的直接基本类型 |
|
UnderlyingSystemType |
该Type在.NET运行库中映射到的类型(某些.NET基类实际上映射到由IL识别的特定预定义类型) |
2.Type的方法
| 返回的对象类型 | 方法 |
| ConstructorInfo | GetConstructor(),GetConstructors() |
| EventInfo | GetEvent(),GetEvents() |
| FieldInfo | GetField(),GetFields() |
| MemberInfo | GetMember(),GetMembers(),GetDefaultMembers() |
| MethodInfo | GetMethod().GetMethods() |
| PropertyInfo | GetProperty(),GetProperties() |
2. System.Reflection.Assembly 类
Assembly 类在System.Reflection名称空间中定义,它允许访问给定程序集的元数据,也可以加载和执行程序集的方法,Assembly类也包含非常多的方法和属性,下面只介绍其常见的用法。
1. 加载相应的程序集有两种方法
/** * 方法一:Assembly.Load() * 参数为程序集的名称,运行库会在各个位置上搜索该程序集,试图找到 * 该程序集,这些位置包括本地目录和全局程序集缓存 */ Assembly assembly1 = Assembly.Load("SomeAssembly"); /** * 方法二:Assembly.LoadFrom() * 参数为程序集的完整路径名,它不会在其他位置搜索该程序集 */ Assembly assembly1 = Assembly.LoadFrom(@"C:\SomeAssembly");
2. 获取在程序集中定义的类型的详细信息
Assembly 类的一个重要功能是它可以获得在相应程序集中定义的所有类型的详细信息,只要调用Assembly.GetTypes()方法,它就可以返回一个包含所有类型的详细信息的System.Type引用数组。
Type[] types = theAssembly.GetTypes(); foreach(Type definedType in types) { DoSomethingWith(definedType); }
3. 获取自定义特性的详细信息
用于查找在程序集或者类型中定义了什么自定义的方法取决于与该特性相关的对象类型。如果要确定程序集从整体上关联了什么自定义的特性,就需要调用Attribute类的一个静态方法 GetCustomAttributes(),给它传递程序集的引用。
//assembly1 为前面提到加载的 Assembly 类
Attribute[] definedAttributes = Attribute.GetCustomAttributes(assembly1);
3. 反射代码示例
在这个示例中,顺带练习了自定义的特性。那么自定义特性有什么用呢?最常见的用途为,可能标记类或者方法的修改时间,修改内容等。当然这也可以在代码中添加注释达到同样的效果。但是,若希望把这些信息写入到文本,注释这种方法是办不到的,而自定义特性能够与对象一样,加载了程序集以后,就可以读取这些特性对象,查看它们的属性,调用它们的方法。
1. 自定义一个特性类,记录类或方法修改的时间以及相应的描述
namespace AttributesTest { [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method,AllowMultiple = true,Inherited = false)] public class LastModifiedAttribute : Attribute { private readonly DateTime _dateModified; private readonly string _changes; public LastModifiedAttribute(string dateModified, string changes) { _dateModified = DateTime.Parse(dateModified); _changes = changes; } public DateTime DateModified { get { return _dateModified; } } public string Changes { get { return _changes; } } public string Issues { get; set; } } }
2. 定义一个接口,以后要更新插件,只需要继承这个接口并实现其中的方法
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace intefacePlugin
{
public interface myInterface
{
int operateNum(int a, int b);
string operateString(string str1, string str2);
}
}
3. 定义插件,并实现接口
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using intefacePlugin; using AttributesTest; namespace myPlugin1 { [LastModified("2018-01-04","添加一个测试插件")] public class plugin1 : myInterface { [LastModified("2018-01-04","两个数相加")] public int operateNum(int a, int b) { return a + b; } [LastModified("2018-01-04","返回较小的字符串")] public string operateString(string str1, string str2) { if (str1.CompareTo(str2) < 0) return str1; else return str2; } } }
4. 利用反射调用插件方法,并调用自定义特性
sing System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; using System.Reflection; using AttributesTest; namespace ReflectionTest { class Program { private static readonly StringBuilder outputText = new StringBuilder(1000); static void Main(string[] args) { //---------调用插件中的函数--------------- Object[] params_obj = new Object[2]; params_obj[0] = 10; params_obj[1] = 5; Assembly plugin = Assembly.Load("myPlugin1"); Type t = plugin.GetType("myPlugin1.plugin1"); MethodInfo operateNum = t.GetMethod("operateNum"); MethodInfo operateString = t.GetMethod("operateString"); //创建该对象的实例,object类型,参数(名称空间+类) object instance = plugin.CreateInstance("myPlugin1.plugin1"); var resInt = operateNum.Invoke(instance, params_obj); params_obj[0] = "Jokey_"; params_obj[1] = "Chan"; var resString = operateString.Invoke(instance, params_obj); Console.WriteLine("resInt = {0}\nresString = {1}", resInt,resString); //-----------打印出插件中的自定义特性------------ Type[] types = plugin.GetTypes(); foreach (Type definedType in types) { DisplayTypeInfo(definedType); } MessageBox.Show(outputText.ToString()); } private static void DisplayTypeInfo(Type type) { if (!type.IsClass) return; AddToMessage("\nclass: " + type.Name); Attribute[] attribs = Attribute.GetCustomAttributes(type); if (0 == attribs.Length) { AddToMessage("No changes to this class"); } else { foreach (var attrib in attribs) { WriteAttributeInfo(attrib); } } MethodInfo[] methods = type.GetMethods(); AddToMessage("CHANGES TO METHODS OF THIS CLASS: "); foreach (var method in methods) { //一个方法可能有多个自定义的特性 object[] attribs2 = method.GetCustomAttributes(typeof(LastModifiedAttribute), false); if (null != attribs2) { AddToMessage(method.ReturnType + " " + method.Name + "()"); foreach (Attribute nextAttrib in attribs2) { WriteAttributeInfo(nextAttrib); } } } } private static void WriteAttributeInfo(Attribute attrib) { LastModifiedAttribute lastModifiedAttrib = attrib as LastModifiedAttribute; if (null == lastModifiedAttrib) return; DateTime modifiedDate = lastModifiedAttrib.DateModified; AddToMessage(" MODIFIED: " + modifiedDate.ToLongDateString() + ":"); AddToMessage(" " + lastModifiedAttrib.Changes); if (null != lastModifiedAttrib.Issues) { AddToMessage(" Outstanding issues:" + lastModifiedAttrib.Issues); } } private static void AddToMessage(string Message) { outputText.Append("\n" + Message); } } }

浙公网安备 33010602011771号