反射
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等)
在程序运行时,动态获取 程序集:
- 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();
-
- 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");
-
-
- }
- }
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中测试
- public void CreatePersonObject() {
- Type type = this.GetType();
-
- Person p = Activator.CreateInstance(type) as Person;
- Person p1 = Activator.CreateInstance<Person>();
-
-
- PropertyInfo prop = type.GetProperty("Name");
- prop.SetValue(p1, "toto");
- Console.WriteLine(p1.Name);
-
-
- 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中
- 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对象得到程序集。
- 根据路径加载程序集
4. Type 类型对象
Type 是一个抽象类,我们用的都是TypeInfo类的对象。
程序运行时,一个class对应一个Type类的对象。通过Type对象可以获得类的所有信息。
获得Type对象的方式:
- 通过类获得对应的Type
- Type t1 = typeof(Person);
- 通过对象获得Type
- Type t2 = person.GetType(); this.GetType();
- 用assembly对象,通过类的full name类获得type对象
- 获得程序集中定义的所有的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:
- 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);
- }
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 TypeTest2()
- {
- Person p = new Person();
- Type tPerson = p.GetType();
- PropertyInfo f = tPerson.GetProperty("Name");
- f.SetValue(p, "titi");
- Console.WriteLine(p.Name);
-
- }
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 TypeTest3()
- {
- Person p = new Person();
- Type tPerson = p.GetType();
-
- MethodInfo[] methodsPublic = tPerson.GetMethods();
-
-
- MethodInfo[] methodsPublicStatic = tPerson.GetMethods(BindingFlags.Public | BindingFlags.Static);
-
- MethodInfo[] methodsPublicInstance = tPerson.GetMethods(BindingFlags.Public | BindingFlags.Instance);
-
- 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:
- static void TypeTest4()
- {
- Person person = new Person();
- Type tPerson = person.GetType();
-
- ConstructorInfo[] constructors = tPerson.GetConstructors();
- foreach (var ctor in constructors)
- {
-
- 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){
-
- 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;
- }
-
-
- 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)});
}
通过反射调用类的私有成员
- 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);
- }
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代码:
- <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#代码:
- 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";
-
- String[] dllFiles = System.IO.Directory.GetFiles(plugInDir, "*.dll");
-
- foreach(String strDll in dllFiles){
-
- Assembly ass = Assembly.LoadFrom(strDll);
-
-
- Type[] types = ass.GetExportedTypes();
- Type notebookInterfaceType = typeof(MyNoteBookPlugInterfaceProject.IPlugIn);
-
- foreach(Type t in types){
-
- if (t.<span style="background-color: rgb(255, 255, 153);">IsAssignableFrom</span>(notebookInterfaceType)) {
-
- PlugInMenuItem.Items.Add(new MenuItem { Header = t.Name });
- }
- }
-
-
-
- }
- }
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这个程序集。
- 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就可以使用了。
- 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>
- <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)