1. 程序集里的元数据 C:\Program Files (x86)\Microsoft SDKs\Windows\v8.0A\bin\NETFX 4.0 Tools\x64\ildasm.exe 用这个工具打开一个assembly。 file -> dump -> dump metainfo, 保存到dump.txt中, 看这个文件。 编译生成il代码,和类的metainfo。 AppDomain 一个程序运行起来以后,有一个AppDomain,在这个AppDomain中放了我们用到的所有assembly。
需要using System.Reflection; Assembly的组成
2. 反射 反射概念: 在程序运行时,动态获取 程序集, 类型(class,interface)和类型的成员信息(方法,字段,属性等)。 在程序运行时,动态创建 类型实例, 以及调用和方法 动态创建出来的 类型实例的成员。 反射的应用:框架(Spring .net/ .Net MVC等) 在程序运行时,动态获取 程序集: [csharp] view plain copy print?
class Program { static void Main(string[] args) { Assembly[] ass = AppDomain.CurrentDomain.GetAssemblies(); Person p = new Person(); p.TestAssembly(); } } class Person { public String Name { get; set; } public int Age { get; set; } private int id; public void TestAssembly() { Assembly ass = this.GetType().Assembly; Type[] types = ass.GetTypes(); Type currentType = ass.GetType(); //根据类的full name,获取在内存中的类型对象 Type typeByFullName = ass.GetType("ConsoleApplication6.Person"); Type type = this.GetType(); MethodInfo[] methods = this.GetType().GetMethods(); this.GetType().GetMembers(); this.GetType().GetMember("Name"); FieldInfo field = type.GetField("id"); PropertyInfo prop = type.GetProperty("Name"); } } 在程序运行时,动态创建 类型实例:在Person类中加下面4个方法,在Main中测试[csharp] view plain copy print?
public void CreatePersonObject() { Type type = this.GetType(); //使用Person类的Type对象,创建一个Person对象 Person p = Activator.CreateInstance(type) as Person; Person p1 = Activator.CreateInstance<Person>(); //使用Person类的Name属性对象,为p的Name属性赋值 PropertyInfo prop = type.GetProperty("Name"); prop.SetValue(p1, "toto"); Console.WriteLine(p1.Name); //使用Person类的Sayhi方法对象,调用p1的Sayhi方法 MethodInfo method = type.GetMethod("Sayhi"); method.Invoke(p1, null); MethodInfo method1 = type.GetMethod("ShowNumber"); object[] arrParams = {2}; method1.Invoke(p1, arrParams); MethodInfo method2 = type.GetMethod("GetString"); String retStr = method2.Invoke(p1, null).ToString(); Console.WriteLine(retStr); } public void Sayhi() { Console.WriteLine("Hiiiiii"); } public void ShowNumber(int no) { Console.WriteLine(no); } public String GetString() { return "Hello"; } 在Main中[csharp] view plain copy print?
Person p = new Person(); p.CreatePersonObject(); 3. Assembly 程序集对象 Assembly 是一个抽象类,我们用的都是RuntimeAssembly的对象。 获得程序集的方式:
static void LoadAssemblyTest() { Assembly ass1 = Assembly.LoadFrom(@"c:\users\xcao\documents\visual studio 2012\Projects\ConsoleApplication6\ConsoleApplication6\libs\Ecole.dll"); Type[] allTypes = ass1.GetTypes(); //GetType的参数一定要是full name的string Type tStu = ass1.GetType("Ecole.Student"); object stu1 = Activator.CreateInstance(tStu); }
4. Type 类型对象 Type 是一个抽象类,我们用的都是TypeInfo类的对象。 程序运行时,一个class对应一个Type类的对象。通过Type对象可以获得类的所有信息。 获得Type对象的方式:
Assembly ass1 = Assembly.LoadFrom(@"c:\users\xcao\documents\visual studio 2012\Projects\ConsoleApplication6\ConsoleApplication6\libs\Ecole.dll"); //GetType的参数一定要是full name的string Type tStu = ass1.GetType("Ecole.Student"); object stu1 = Activator.CreateInstance(tStu);
Type类的属性:
Type类的方法:
Type类的示例1:[csharp] view plain copy print?
static void TypeTest1() { Person p = new Person { Name = "toto", Age = 5}; Type tPerson = p.GetType(); PropertyInfo[] props = tPerson.GetProperties(); StringBuilder builder = new StringBuilder(30); foreach (PropertyInfo prop in props) { builder.Append(prop.Name + "=" + prop.GetValue(p) + "\n"); } builder.Append("------------------------------- \n"); FieldInfo[] fields = tPerson.GetFields(); foreach(FieldInfo f in fields){ builder.Append(f.Name + "=" + f.GetValue(p) + "\n"); } Console.WriteLine(builder); } Type类的示例2:[csharp] view plain copy print?
static void TypeTest2() { Person p = new Person(); Type tPerson = p.GetType(); PropertyInfo f = tPerson.GetProperty("Name"); f.SetValue(p, "titi"); Console.WriteLine(p.Name); } Type类的示例3:[csharp] view plain copy print?
static void TypeTest3() { Person p = new Person(); Type tPerson = p.GetType(); //所有的public方法 MethodInfo[] methodsPublic = tPerson.GetMethods(); //为了获取返回值,必须指定 BindingFlags.Instance 或 BindingFlags.Static。 //public 的 static 的方法 MethodInfo[] methodsPublicStatic = tPerson.GetMethods(BindingFlags.Public | BindingFlags.Static); //public 的 实例方法 MethodInfo[] methodsPublicInstance = tPerson.GetMethods(BindingFlags.Public | BindingFlags.Instance); //只是在类中定义的(不包括继承的)public的 实例的 和static的 方法 MethodInfo[] methodsPublicDeclareOnly = tPerson.GetMethods(BindingFlags.Public | BindingFlags.Instance| BindingFlags.DeclaredOnly | BindingFlags.Static); } Type类示例4:[csharp] view plain copy print?
static void TypeTest4() { Person person = new Person(); Type tPerson = person.GetType(); //得到所有的共有构造函数 ConstructorInfo[] constructors = tPerson.GetConstructors(); foreach (var ctor in constructors) { //Name都是 .ctor Console.WriteLine(ctor.Name); //构造函数的参数个数 Console.WriteLine(ctor.GetParameters().Length); ParameterInfo[] parametres = ctor.GetParameters(); foreach (var p in parametres) { Console.WriteLine(p.Name + " : " + p.ParameterType); } } Person person1, person2; // 调用指定参数的 构造函数 创建对象 ConstructorInfo c1 = tPerson.GetConstructor(new Type[2] { typeof(String), typeof(int) }); if(c1 != null){ //通过构造函数的invoke方法来创建对象, 创建出来的对象 是invoke方法的返回值(object类型) person1 = c1.Invoke(new object[] { "toto", 2 }) as Person; } // 调用无参数的构造函数 创建对象 ConstructorInfo c2 = tPerson.GetConstructor(new Type[0]); if (c2 != null) { person2 = c2.Invoke(null) as Person; } // 没有一个参数为String的构造函数, 返回null ==> c3为null ConstructorInfo c3 = tPerson.GetConstructor(new Type[] { typeof(String)}); } 通过反射调用类的私有成员 [csharp] view plain copy print?
static void TypeTest5() { Person person = new Person(); Type tPerson = person.GetType(); MethodInfo privateMethod = tPerson.GetMethod("TestPrivateMethod", BindingFlags.Instance | <span style="background-color: rgb(255, 255, 153);">BindingFlags.NonPublic</span>); privateMethod.Invoke(person, null); } 类中的public private是针对compiler的, compiler负责语法检查。 运行时 是没有 public private限制的,只要代码到内存中,就可以调用执行。 5. 记事本程序实例 xmal代码:[html] view plain copy print?
<Window x:Class="MyNoteBookProject.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="MainWindow" Height="350" Width="525" Loaded="Window_Loaded"> <DockPanel> <Menu DockPanel.Dock="Top" HorizontalAlignment="Left" VerticalAlignment="Top"> <MenuItem Header="File"> <MenuItem Header="New"></MenuItem> <MenuItem Header="Open"></MenuItem> <MenuItem Header="Add"></MenuItem> </MenuItem> <MenuItem Header="Edit"> <MenuItem Header="Cut"></MenuItem> <MenuItem Header="Copy"></MenuItem> <MenuItem Header="Paste"></MenuItem> </MenuItem> <MenuItem Header="Extend" Name="PlugInMenuItem"></MenuItem> </Menu> <TextBox DockPanel.Dock="Bottom" Name="txt"></TextBox> </DockPanel> </Window> c#代码:[csharp] view plain copy print?
private void Window_Loaded(object sender, RoutedEventArgs e) { AddPlugInsToMenu(); } //读取程序集文件,并生成 插件按钮 private void AddPlugInsToMenu() { // 获取正在运行的程序集 的 物理路径 String assPath = this.GetType().Assembly.Location; // 获取 程序集 所有文件夹 String assDirPath = System.IO.Path.GetDirectoryName(assPath); // 插件文件夹的路径 String plugInDir = assDirPath + "\\plugs"; // 扫描插件文件夹中的 所有 程序集文件名(获取所有dll文件) String[] dllFiles = System.IO.Directory.GetFiles(plugInDir, "*.dll"); // 遍历程序集文件,并加载程序集文件到内存 foreach(String strDll in dllFiles){ // 根据程序集路径 加载程序集 到内存 Assembly ass = Assembly.LoadFrom(strDll); // 判断程序集中是否有插件类 // 获取程序集中的public类 Type[] types = ass.GetExportedTypes(); Type notebookInterfaceType = typeof(MyNoteBookPlugInterfaceProject.IPlugIn); // 判断是否实现了记事本接口 foreach(Type t in types){ // 判断t是否实现了 notebookInterfaceType 接口 if (t.<span style="background-color: rgb(255, 255, 153);">IsAssignableFrom</span>(notebookInterfaceType)) { // 根据插件类,创建menuitem,并添加到menu中 PlugInMenuItem.Items.Add(new MenuItem { Header = t.Name }); } } //// 创建menuitem,并添加到menu中 //PlugInMenuItem.Items.Add(new MenuItem { Header = strDll}); } } 另一个记事本公司开发的dll中, 有一个接口, 在wpf程序中add ref这个程序集。其他开发plugin的公司,也必须add ref这个程序集。[csharp] view plain copy print?
namespace MyNoteBookPlugInterfaceProject { public interface IPlugIn { String ProcessText(String text); } } 开发plugin的公司:写一个class library project, 也add ref记事本公司开发的接口程序集。写实现了这个接口的插件类。build这个程序集,把dll放到记事本项目的plugInDir目录下。这个plugin就可以使用了。[csharp] view plain copy print?
namespace NoteBookPlugIn { public class PlugToUpper : MyNoteBookPlugInterfaceProject.IPlugIn { public string ProcessText(string text) { return text.ToUpper(); } } }</strong> [csharp] view plain copy print?
<strong>namespace NoteBookPlugIn { public class PlugToLower : IPlugIn { public string ProcessText(string text) { return text.ToLower(); } } } 运行结果:
6. 动态创建对象 1. 通过Activator创建 object o = Activator.CreateInstance(Type type); 会调用无参数的构造函数创建一个对象,如果没有无参数的构造函数,异常。 2. 通过 构造器 创建(Type类示例4)