前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >C#反射原理解析

C#反射原理解析

作者头像
bering
发布2019-12-03 14:49:47
1.1K0
发布2019-12-03 14:49:47
举报
文章被收录于专栏:游戏开发之旅游戏开发之旅

反射

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?

  1. class Program
  2. {
  3. static void Main(string[] args)
  4. {
  5. Assembly[] ass = AppDomain.CurrentDomain.GetAssemblies();
  6. Person p = new Person();
  7. p.TestAssembly();
  8. }
  9. }
  10. class Person {
  11. public String Name { get; set; }
  12. public int Age { get; set; }
  13. private int id;
  14. public void TestAssembly() {
  15. Assembly ass = this.GetType().Assembly;
  16. Type[] types = ass.GetTypes();
  17. Type currentType = ass.GetType();
  18. //根据类的full name,获取在内存中的类型对象
  19. Type typeByFullName = ass.GetType("ConsoleApplication6.Person");
  20. Type type = this.GetType();
  21. MethodInfo[] methods = this.GetType().GetMethods();
  22. this.GetType().GetMembers();
  23. this.GetType().GetMember("Name");
  24. FieldInfo field = type.GetField("id");
  25. PropertyInfo prop = type.GetProperty("Name");
  26. }
  27. }

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?

  1. public void CreatePersonObject() {
  2. Type type = this.GetType();
  3. //使用Person类的Type对象,创建一个Person对象
  4. Person p = Activator.CreateInstance(type) as Person;
  5. Person p1 = Activator.CreateInstance<Person>();
  6. //使用Person类的Name属性对象,为p的Name属性赋值
  7. PropertyInfo prop = type.GetProperty("Name");
  8. prop.SetValue(p1, "toto");
  9. Console.WriteLine(p1.Name);
  10. //使用Person类的Sayhi方法对象,调用p1的Sayhi方法
  11. MethodInfo method = type.GetMethod("Sayhi");
  12. method.Invoke(p1, null);
  13. MethodInfo method1 = type.GetMethod("ShowNumber");
  14. object[] arrParams = {2};
  15. method1.Invoke(p1, arrParams);
  16. MethodInfo method2 = type.GetMethod("GetString");
  17. String retStr = method2.Invoke(p1, null).ToString();
  18. Console.WriteLine(retStr);
  19. }
  20. public void Sayhi() {
  21. Console.WriteLine("Hiiiiii");
  22. }
  23. public void ShowNumber(int no) {
  24. Console.WriteLine(no);
  25. }
  26. public String GetString() {
  27. return "Hello";
  28. }

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?

  1. Person p = new Person();
  2. p.CreatePersonObject();

Person p = new Person(); p.CreatePersonObject(); 3. Assembly 程序集对象 Assembly 是一个抽象类,我们用的都是RuntimeAssembly的对象。 获得程序集的方式:

  • 获得当前程序域中的所有程序集
    • Assembly[] ass = AppDomain.CurrentDomain.GetAssemblies();
    • 所有用到过得aessembly。如果只是add ref了,没有在程序中用到,AppDomain.CurrentDomain.GetAssemblies()中没有。用到时才被JIT加载到内存。
    • 每个app都有一个AppDomain,OS不允许其他app访问这个程序的AppDomain
  • 获得当前对象所属的类所在的程序集
    • this.GetType().Assembly;
    • Type对象肯定在一个assembly对象中
    • 可以通过Type对象得到程序集。
  • 根据路径加载程序集
    • Assembly.LoadFrom(assPath);
    • [csharp] view plain copy print?
      1. static void LoadAssemblyTest() {
      2. Assembly ass1 = Assembly.LoadFrom(@"c:\users\xcao\documents\visual studio 2012\Projects\ConsoleApplication6\ConsoleApplication6\libs\Ecole.dll");
      3. Type[] allTypes = ass1.GetTypes();
      4. //GetType的参数一定要是full name的string
      5. Type tStu = ass1.GetType("Ecole.Student");
      6. object stu1 = Activator.CreateInstance(tStu);
      7. }

      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对象的方式:

  • 通过类获得对应的Type
    • Type t1 = typeof(Person);
  • 通过对象获得Type
    • Type t2 = person.GetType(); this.GetType();
  • 用assembly对象,通过类的full name类获得type对象
    • [csharp] view plain copy print?
      1. Assembly ass1 = Assembly.LoadFrom(@"c:\users\xcao\documents\visual studio 2012\Projects\ConsoleApplication6\ConsoleApplication6\libs\Ecole.dll");
      2. //GetType的参数一定要是full name的string
      3. Type tStu = ass1.GetType("Ecole.Student");
      4. object stu1 = Activator.CreateInstance(tStu);

      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);

  • 获得程序集中定义的所有的public类
    • Type[] allPublicTypes = ass1.GetExportedTypes();
  • 获得程序集中定义的所有的类
    • Type[] allTypes = ass1.GetTypes();

Type类的属性:

    • t.Assembly; 获取t所在的程序集
    • t.FullName; 获取t所对应的类的full name
    • t.Name; 获取t所对应的类的 name
    • t.IsArray; 判断t是否是一个数组类
    • t.IsEnum; 判断t是否是一个枚举类
    • t.IsAbstract; 判断t是否是一个抽象类
    • t.IsInterface; 判断t是否是一个interface

Type类的方法:

    • notebookInterfaceType.IsAssignableFrom(Type t);判断t是否实现了 notebookInterfaceType 接口
    • t.IsSubclassOf(Type parent); t是否是parent的子类
    • t.IsInstanceOfType(object o); o是否是t类的对象
    • t.GetFields(); //method, property 得到所有的public的fields,methods,properties
    • t.GetField("gender"); 根据名字得到某个field

Type类的示例1:[csharp] view plain copy print?

  1. static void TypeTest1() {
  2. Person p = new Person { Name = "toto", Age = 5};
  3. Type tPerson = p.GetType();
  4. PropertyInfo[] props = tPerson.GetProperties();
  5. StringBuilder builder = new StringBuilder(30);
  6. foreach (PropertyInfo prop in props)
  7. {
  8. builder.Append(prop.Name + "=" + prop.GetValue(p) + "\n");
  9. }
  10. builder.Append("------------------------------- \n");
  11. FieldInfo[] fields = tPerson.GetFields();
  12. foreach(FieldInfo f in fields){
  13. builder.Append(f.Name + "=" + f.GetValue(p) + "\n");
  14. }
  15. Console.WriteLine(builder);
  16. }

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?

  1. static void TypeTest2()
  2. {
  3. Person p = new Person();
  4. Type tPerson = p.GetType();
  5. PropertyInfo f = tPerson.GetProperty("Name");
  6. f.SetValue(p, "titi");
  7. Console.WriteLine(p.Name);
  8. }

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?

  1. static void TypeTest3()
  2. {
  3. Person p = new Person();
  4. Type tPerson = p.GetType();
  5. //所有的public方法
  6. MethodInfo[] methodsPublic = tPerson.GetMethods();
  7. //为了获取返回值,必须指定 BindingFlags.Instance 或 BindingFlags.Static。
  8. //public 的 static 的方法
  9. MethodInfo[] methodsPublicStatic = tPerson.GetMethods(BindingFlags.Public | BindingFlags.Static);
  10. //public 的 实例方法
  11. MethodInfo[] methodsPublicInstance = tPerson.GetMethods(BindingFlags.Public | BindingFlags.Instance);
  12. //只是在类中定义的(不包括继承的)public的 实例的 和static的 方法
  13. MethodInfo[] methodsPublicDeclareOnly = tPerson.GetMethods(BindingFlags.Public | BindingFlags.Instance| BindingFlags.DeclaredOnly | BindingFlags.Static);
  14. }

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?

  1. static void TypeTest4()
  2. {
  3. Person person = new Person();
  4. Type tPerson = person.GetType();
  5. //得到所有的共有构造函数
  6. ConstructorInfo[] constructors = tPerson.GetConstructors();
  7. foreach (var ctor in constructors)
  8. {
  9. //Name都是 .ctor
  10. Console.WriteLine(ctor.Name);
  11. //构造函数的参数个数
  12. Console.WriteLine(ctor.GetParameters().Length);
  13. ParameterInfo[] parametres = ctor.GetParameters();
  14. foreach (var p in parametres)
  15. {
  16. Console.WriteLine(p.Name + " : " + p.ParameterType);
  17. }
  18. }
  19. Person person1, person2;
  20. // 调用指定参数的 构造函数 创建对象
  21. ConstructorInfo c1 = tPerson.GetConstructor(new Type[2] { typeof(String), typeof(int) });
  22. if(c1 != null){
  23. //通过构造函数的invoke方法来创建对象, 创建出来的对象 是invoke方法的返回值(object类型)
  24. person1 = c1.Invoke(new object[] { "toto", 2 }) as Person;
  25. }
  26. // 调用无参数的构造函数 创建对象
  27. ConstructorInfo c2 = tPerson.GetConstructor(new Type[0]);
  28. if (c2 != null)
  29. {
  30. person2 = c2.Invoke(null) as Person;
  31. }
  32. // 没有一个参数为String的构造函数, 返回null ==> c3为null
  33. ConstructorInfo c3 = tPerson.GetConstructor(new Type[] { typeof(String)});
  34. }

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?

  1. static void TypeTest5() {
  2. Person person = new Person();
  3. Type tPerson = person.GetType();
  4. MethodInfo privateMethod = tPerson.GetMethod("TestPrivateMethod", BindingFlags.Instance | <span style="background-color: rgb(255, 255, 153);">BindingFlags.NonPublic</span>);
  5. privateMethod.Invoke(person, null);
  6. }

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?

  1. <Window x:Class="MyNoteBookProject.MainWindow"
  2. xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  3. xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  4. Title="MainWindow" Height="350" Width="525" Loaded="Window_Loaded">
  5. <DockPanel>
  6. <Menu DockPanel.Dock="Top" HorizontalAlignment="Left" VerticalAlignment="Top">
  7. <MenuItem Header="File">
  8. <MenuItem Header="New"></MenuItem>
  9. <MenuItem Header="Open"></MenuItem>
  10. <MenuItem Header="Add"></MenuItem>
  11. </MenuItem>
  12. <MenuItem Header="Edit">
  13. <MenuItem Header="Cut"></MenuItem>
  14. <MenuItem Header="Copy"></MenuItem>
  15. <MenuItem Header="Paste"></MenuItem>
  16. </MenuItem>
  17. <MenuItem Header="Extend" Name="PlugInMenuItem"></MenuItem>
  18. </Menu>
  19. <TextBox DockPanel.Dock="Bottom" Name="txt"></TextBox>
  20. </DockPanel>
  21. </Window>

<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?

  1. private void Window_Loaded(object sender, RoutedEventArgs e)
  2. {
  3. AddPlugInsToMenu();
  4. }
  5. //读取程序集文件,并生成 插件按钮
  6. private void AddPlugInsToMenu() {
  7. // 获取正在运行的程序集 的 物理路径
  8. String assPath = this.GetType().Assembly.Location;
  9. // 获取 程序集 所有文件夹
  10. String assDirPath = System.IO.Path.GetDirectoryName(assPath);
  11. // 插件文件夹的路径
  12. String plugInDir = assDirPath + "\\plugs";
  13. // 扫描插件文件夹中的 所有 程序集文件名(获取所有dll文件)
  14. String[] dllFiles = System.IO.Directory.GetFiles(plugInDir, "*.dll");
  15. // 遍历程序集文件,并加载程序集文件到内存
  16. foreach(String strDll in dllFiles){
  17. // 根据程序集路径 加载程序集 到内存
  18. Assembly ass = Assembly.LoadFrom(strDll);
  19. // 判断程序集中是否有插件类
  20. // 获取程序集中的public类
  21. Type[] types = ass.GetExportedTypes();
  22. Type notebookInterfaceType = typeof(MyNoteBookPlugInterfaceProject.IPlugIn);
  23. // 判断是否实现了记事本接口
  24. foreach(Type t in types){
  25. // 判断t是否实现了 notebookInterfaceType 接口
  26. if (t.<span style="background-color: rgb(255, 255, 153);">IsAssignableFrom</span>(notebookInterfaceType)) {
  27. // 根据插件类,创建menuitem,并添加到menu中
  28. PlugInMenuItem.Items.Add(new MenuItem { Header = t.Name });
  29. }
  30. }
  31. //// 创建menuitem,并添加到menu中
  32. //PlugInMenuItem.Items.Add(new MenuItem { Header = strDll});
  33. }
  34. }

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?

  1. namespace MyNoteBookPlugInterfaceProject
  2. {
  3. public interface IPlugIn
  4. {
  5. String ProcessText(String text);
  6. }
  7. }

namespace MyNoteBookPlugInterfaceProject { public interface IPlugIn { String ProcessText(String text); } } 开发plugin的公司:写一个class library project, 也add ref记事本公司开发的接口程序集。写实现了这个接口的插件类。build这个程序集,把dll放到记事本项目的plugInDir目录下。这个plugin就可以使用了。[csharp] view plain copy print?

  1. namespace NoteBookPlugIn
  2. {
  3. public class PlugToUpper : MyNoteBookPlugInterfaceProject.IPlugIn
  4. {
  5. public string ProcessText(string text)
  6. {
  7. return text.ToUpper();
  8. }
  9. }
  10. }</strong>

namespace NoteBookPlugIn { public class PlugToUpper : MyNoteBookPlugInterfaceProject.IPlugIn { public string ProcessText(string text) { return text.ToUpper(); } } }</strong> [csharp] view plain copy print?

  1. <strong>namespace NoteBookPlugIn
  2. {
  3. public class PlugToLower : IPlugIn
  4. {
  5. public string ProcessText(string text)
  6. {
  7. return text.ToLower();
  8. }
  9. }
  10. }

<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)

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2018-05-31 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 反射
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档