C#4.0图解教程

24.1 元数据和反射

有关程序及类型的数据被成为 元数据他们保存在程序集中

程序运行时,可以查看其他程序集或其本身的元数据。一个运行的程序查看本身元数据或其他程序的元数据的行为叫做 反射

反射

24.2  Type 类

System.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;
}
}

获取

image

调用

image

//6.相当于:d2.name=”小白”;

//7.相当于:d2.ShoutHi();

2.Assembly 程序集对象

获取程序集的方式:

2.1.获得当前 程序域中 所有的Assembly

               AppDomain.CurrentDomain.GetAssemblies()

Assembly[] ass = AppDomain.CurrentDomain.GetAssemblies();

ass调用的所有Assembly

image

 

2.2.获取当前 对象 所在的 Assembly:

               this.GetType().Assembly

//1.获取当前正在运行的 程序集(Assembly)对象
Assembly ass = this.GetType().Assembly;

image

 

2.3.根据路径加载Assembly :

               Assembly.LoadFrom(assPath)
image

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

image

案例:笔记本插件开发

SNAGHTML14d0eb6

plugs文件夹

image

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

image

结果:

SNAGHTML14f7f53

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));
 
 
7.MethodInfo 方法对象
MethodInfo类 代表某个类中的一个方法
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},
res2:{1}", res1, res2));

第一个参数是实例对象,第二个参数是方法的参数数组,如果没有参数设置为null
问:如果第一个参数传 null 呢?

image
 

8.动态创建对象

image

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));
image
案例:
Cat.cs
    class Cat
    {
        public string name;
        public int age;
        //构造函数
        public Cat(string name, int age)
        {
            this.name = name;
            this.age = age;
        }
    }

image

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
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

原文地址:https://www.cnblogs.com/tangge/p/3440605.html