24.1 元数据和反射
有关程序及类型的数据被成为 元数据。他们保存在程序集中。
程序运行时,可以查看其他程序集或其本身的元数据。一个运行的程序查看本身元数据或其他程序的元数据的行为叫做 反射。
24.2 Type 类
Name | 属性 | 返回类型的名字 |
Namespace | 属性 | 返回包含类型的命名空间 |
Assembly | 属性 | 返回声明类型的程序集。如果类型是泛型,返回定义这个类型的程序集 |
GetFields | 方法 | 返回类型的字段列表 |
GetProperties | 方法 | 返回类型的属性列表 |
GetMethods | 方法 | 返回类型的方法列表 |
1.反射概念:
1.在程序运行时,
动态 获取 加载程序集
动态 获取 类型(如类、接口 等)
动态 获取 类型的成员 信息(如方法,字段,属性等);
2.在运行时,动态创建类型实例,以及 调用 和 访问 这些 实例 成员;
namespace _01反射
{
class Dog
{
public string name;
public int age;
private bool gender;
public string ShoutHi()
{
return this.name + "," + this.age + "," + this.gender;
}
}
获取
调用
//6.相当于:d2.name=”小白”;
//7.相当于:d2.ShoutHi();
2.Assembly 程序集对象
获取程序集的方式:
2.1.获得当前 程序域中 所有的Assembly:
AppDomain.CurrentDomain.GetAssemblies()
Assembly[] ass = AppDomain.CurrentDomain.GetAssemblies();
ass调用的所有Assembly
2.2.获取当前 对象 所在的 Assembly:
this.GetType().Assembly
//1.获取当前正在运行的 程序集(Assembly)对象
Assembly ass = this.GetType().Assembly;
2.3.根据路径加载Assembly :
Assembly.LoadFrom(assPath)
3.Type 类型对象
Type类,程序运行时一个 class 对应一个 Type类的对象。
通过Type对象可以获得类的所有的定义信息,比如类有哪些属性、哪些方法等
获得Type对象的方式:
1.通过类 获得 对应 Type:Type t = typeof(Person)
2.通过对象 获得 Type:Type t = p.GetType()
3.根据类的全名称 获取程序集中定义的类:
Type type = Assembly.GetType("BLL.Person")
Type tDog = ass.GetType("_01反射.Dog"); //全名称(带命名空间)
4.获取程序集中定义的所有的public类:
Type [] types = assembly.GetExportedTypes()
5.获取程序集中定义的所有的类型:
Type [] types = assembly.GetTypes()
Assembly ass = this.GetType().Assembly;
//获取此程序集中定义的公共类型,这些公共(public)类型在程序集外可见. (ispublic = true)
Type[] types = ass.GetExportedTypes();
// 获取此程序集中定义的所有类型
Type[] tyoe = ass.GetTypes();
//1.通过类 直接过去 类型对象
Type t2 = typeof(Dog);
//2.通过对象 来获取 类型对象
Type t3 = this.GetType();
案例:笔记本插件开发
plugs文件夹
namespace C02记事本插件
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
makeBrntBll();
}
//读取程序集,并生成插件
public void makeBrntBll()
{
//1.加载正在运行程序的物理路径
string strRunAss = this.GetType().Assembly.Location;
//2.获取程序集坐在文件夹,并转换成插件文件夹路径
string AssPath = Path.GetDirectoryName(strRunAss)+"\\plugs";
//3.扫描插件文件夹里面的所有程序集文件
string[] strDrictoryPath = Directory.GetFiles(AssPath, "*.dll");
//4.遍历程序集文件 路径,并加载到内存中
foreach (var strItem in strDrictoryPath)
{
//4.1根据路径 加载到内存中
Assembly ass = Assembly.LoadFrom(strItem);
//4.2判断程序集中是否有插件类
//4.3创建插件按钮
ToolStripMenuItem menuItem = new ToolStripMenuItem("发现一个插件");
this.插件扩展ToolStripMenuItem.DropDownItems.Add(menuItem);
}
}
}
}
结果:
4.Type 的成员
属性 |
|
type.Assembly | 获取type所在的程序集对象 |
type.FullName | 获取type对象对应的类的全名称 |
type.Name | 获取type对象对应类的 名称 |
type.IsArray | 判断type是否为一个数组类 |
type.IsEnum | 判断type是否为一个枚举类 |
方法 | |
type.IsAssignableFrom(Type i) | 判断type是否实现了接口 i |
type.IsSubclassOf(Type father) | 判断type是否继承了 father |
type.IsInstanceOfType(object o) | 判断 o 是否为type类的实例 |
type.GetFiled("gender") | 获取type中名为gender的字段对象 |
type.GetMethod("SayHi") | 获取type中名为 SayHi 的方法对象 |
type.GetProperty("Age") | 获取type中名为 Age 的属性对象 |
5.FieldInfo 字段对象
FieldInfo类 代表某个类中的一个成员字段(类的全局变量)
public class Dog
{
public string dogName;
public int dogAge;
}
操作 对象 的字段
Dog dObj = new Dog() { dogName = "小花", dogAge = 1 }; //dogName:小花,dogAge:1 Console.WriteLine(string.Format("dogName:{0},dogAge:{1}",dObj.dogName,dObj.dogAge)); Type dType = dObj.GetType();//获取类型 FieldInfo fiDN = dType.GetField("dogName"); //获取字段对象 //相当于string strName = dObj.dogName; string strName = fiDN.GetValue(dObj).ToString(); //获取dObj的dogName字段值,strName=“小花” fiDN.SetValue(dObj, "小白"); //设置dObj里的dogName字段值 //dogName:小白,dogAge:1 Console.WriteLine(string.Format("dogName:{0},dogAge:{1}", dObj.dogName, dObj.dogAge));
6.PropertyInfo 属性对象
PropertyInfo类 代表某个类中的一个属性
public class Dog
{
public string Name{get;set;}
public int Age{get;set;}
}
Dog dObj = new Dog() { Name = "小花", Age = 1 }; Console.WriteLine(string.Format("dogName:{0},dogAge:{1}", dObj.Name, dObj.Age)); Type dType = dObj.GetType(); PropertyInfo piN = dType.GetProperty("Name"); //获取属性对象 string strName = piN.GetValue(dObj, null).ToString(); //获取dObj的Name属性值 piN.SetValue(dObj, "小白", null); //设置dObj里的Name属性值 Console.WriteLine(string.Format("dogName:{0},dogAge:{1}", dObj.Name, dObj.Age));
public class Dog
{
public string Smile(string name)
{
return "一只会笑的狗:"+name;
}
}
调用 对象 的方法
Dog dObj = new Dog(); Type dType = dObj.GetType(); MethodInfo method = dType.GetMethod("Smile"); //获取方法对象 object res1 = dObj.Smile("小五~~");//*普通调用方法 object res2 = method.Invoke(dObj, new object[] { "小白" }); //*反射调用dObj的Smile方法 Console.WriteLine(string.Format("res1:{0},\r\nres2:{1}", res1, res2));
第一个参数是实例对象,第二个参数是方法的参数数组,如果没有参数设置为null
问:如果第一个参数传 null 呢?
8.动态创建对象
1.object res =Activator.CreateInstance(Type type)
会动态调用类的无参构造函数创建一个对象
返回值就是创建的对象,如果类没有无参构造函数就会报错。
2.使用 构造器 创建
//构造函数 //public Dog(){} public Dog(string name, int age){ this.Name = name; this.Age = age; }
Type dType = typeof(Dog);//获取 Dog类 类型 对象 //获取 构造器 对象(根据 参数列表的 参数类型 数组 获取) ConstructorInfo cotr = dType.GetConstructor(new Type[] { typeof(string), typeof(int) }); object resValue = cotr.Invoke(new object[] { "小白", 2 }); //调用指定参数的实例所反映的构造函数cotr Console.WriteLine(string.Format("Name:{0},Age:{1}", ((Dog)(resValue)).Name, ((Dog)(resValue)).Age));
class Cat { public string name; public int age; //构造函数 public Cat(string name, int age) { this.name = name; this.age = age; } }
9.调用对象私有成员
Person p1 = new Person();
Type type = p1.GetType();
//BindingFlags.Instance表示是实例方法,也就是不是static方法
MethodInfo mHaha = type.GetMethod("Haha",BindingFlags.NonPublic | BindingFlags.Instance);
mHaha.Invoke(p1, null);
作者:唐三三
出处:http://tangge.cnblogs.com
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。