反射
反射
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中测试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"); } }
[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";
- }
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();
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?
- 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);
- }
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?
- 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);
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类的方法:
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: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); }
[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:static void TypeTest2() { Person p = new Person(); Type tPerson = p.GetType(); PropertyInfo f = tPerson.GetProperty("Name"); f.SetValue(p, "titi"); Console.WriteLine(p.Name); }
[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);
- }
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)});
- }
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限制的,只要代码到内存中,就可以调用执行。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); }
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>
<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这个程序集。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}); } }
[csharp] view plain copy print?
- namespace MyNoteBookPlugInterfaceProject
- {
- public interface IPlugIn
- {
- String ProcessText(String text);
- }
- }
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>
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();
- }
- }
- }
<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)
相关阅读
C#中Console.WriteLine()函数输出格式详解
格式项都采用如下形式: {index[,alignment][:formatString]} 其中"index"指索引占位符,这个肯定都知道; ",alignment"按字面意思显
本文来自https://www.cnblogs.com/Mculover666/p/9126191.html 1、新建C#项目工程 首先选择新建Windows窗体应用(.NET Framewor
除了网上提到的众多原因,这里提到的是另一种情况,也会有以下提示产生。 该情况下代码无问题,原因是提示有问题的代码句或段在整段代
C# ——Ibatis底层搭建 参考博客 链接: [link]https://blog.csdn.net/mofeimo110/article/details/72625638 系列一、二后,得到两
C#——Console.WriteLine("{0}{1}")中的{0}{1}是什
下面一个例子可以更直观的说明作用 namespace ConsoleApplication1{class Program{static void Main(string[] args){ int a