C# 反射
C#编译过程:
C#语言——>编译器编译——>DLL/EXE(metadate元数据、IL中间语言)(确定具体类型)——>CLR/JIT——>机器码01010101——>电脑
EXE/DLL的主要区别在于是否有Main函数入口
metadata元数据:描述EXE/DLL文件的一个数据清单
JIT通过访问元数据确定具体类型后,才会继续编译为机器码
反射用来操作获取元数据(matedata)
反射是什么:
反射就是一个操作metadata的一个类库(可以把反射当成一个小工具用来读取或者操作元数据)操作 类、方法、特性、属性字段。
为什么要通过反射间接去操作:
- 因为我们需要动态
- 读取私有的对象
{
- 更新程序时(更新自己的DLL)
- 使用别人的DLL文件(这种可以读取别人的私有的东西)
}
使用到反射的地方:
asp.net MVC ---ORM ---LOC ---AOP 几乎所有的框架都会使用反射
通过反射加载DLL文件
加载方式一:通过DLL文件名进行加载
需要将文件添加到项目引用 才能够进行使用否则使用完全路径
Assembly assembly = Assembly.Load("DLL文件名");  
foreach(var it in assembly.GetTypes())//返回工程下所有的类
{
    Console.WriteLine(it.Name);
    foreach(var fun in it.GetMethods) //返回所有方法的名称
    {
        Console.WriteLine("这是"+fun.Name+"方法");
    }
}加载方式二:完整路径(详细路径)
Assembly assembly = Assembly.LoadFile("@完整路径");加载方式三:完全限定名
Assembly assembly = LoadForm("DLL文件名加上拓展名");
Assembly assembly = LoadForm("@完整路径");使用反射创建对象
Assembly assembly = Assembly.LoadForm("DLL文件名加上拓展名");//加载DLL文件
Type type = assembly.GetType("命名空间.类名");//获取类型(需要完整的类型名称)
object oDbHelper = Activator.CreateInstance(type);//创建对象  不确定类型定义object装箱使用
//相当于new一个对象
//创建父类对象用来接受odject对象的转换 然后调用自身方法使用反射创建带参数对象
//通过反射读取DLL元数据
Assembly assembly = Assembly.LoadForm("DLL文件名+后缀名");
//加载类型
Type type = assembly.GetType("命名空间.类名");
{
    //获取到这个类型下面所有的构造方法
    foreach(ConstructorInfo cotor in type.GetConstructors())//获取到所有的构造方法
    {
        Console.WriteLine(ctor.Name);
        foreach(var parameter in ctor.GetParameters())//获取到构造方法的所有参数类型
        {
            Console.WriteLine(parameter.ParameterType);//显示类型名称
        }
    }
}
//创建带带参数对象
object Ocotr = Activator.CreateInstance(type,new object[]{传入参数});使用反射创建对象(私有构造函数)
通过这种方式也可以破坏单例
Assembly assemby = Assembly.LoadFrom("DLL文件名+后缀名");
Type type = assembly.GetType("命名空间.类名");
//创建私有构造函数对象
object oPrivate = Activator.Createlnstance(type,true);  //后一个参数确定构造是否为私有使用反射创建泛型类
Assembly assembly = Assembly.LoadFrom("DLL文件名+后缀名");
Type type = assembly.GetType("命名空间.类名+`+类型个数");//需要在末尾加上反单引号和类型个数进行占位
Type makeType = type.MakeGenericType(new Type[]{typeof(int),typeof(string),typeof(double)});//在数组内传入需要的类型
object oGeneric = Active.CreateInstance(makeType); 使用反射调用方法
Assembky assembly = Assembly.LoadFrom("DLL文件名+后缀名");
Type type = assembly.GetType("命名空间.类名");
object oReflection = Activator.CreateInstance(type);
//获取方法名
foreach(var method in type.GetMethods())
{
    //获取方法名
    Console.WriteLine(method.Name);
    //获取方法参数
    foreach(var parameter in method.GetParameters())
    {
        Console.WriteLine(parameter.Name+" "+parameter.ParameterType);
    }
}
//调用无参方法
//获取方法
MethodInfo methodInfo = type.GetMethod("方法名");
methodInfo.Invoke(oReflection,null); //调用方法
//调用有参方法
MethodInfo methodInfo = type.GetMethod("方法名");
methodInfo.Invoke(oReflection,new object[]{传入参数});
//调用重载方法
//获取方法时 给到对应参数类型
MethodInfo methodInfo = type.GetMethod("方法名",new Type[]{typeof(类型)}...);
methodInfo.Invoke(oReflection,new object[]{传入对应类型参数});
//无参数重载
MethodInfo methodInfo = type.GetMethod("方法名",new Type[]{});
methodInfo.Invoke(oReflection,null);
//静态方法的调用
MethodInfo methodInfo = type.GetMethod("方法名");
methodInfo.Invoke(oReflection,new object[]{传入参数});//调用方法
{
    //另一种调用方法
    MethodInfo methodInfo = type.GetMethod("方法名");
    methodInfo.Invoke(null,new object[]{传入参数});
}使用反射调用私有方法
需要在获取方法的时候添加BindingFlags.Instance|BinDingFlags.NonPubliction两个参数 来说明此方法为实例非公开的方法
Assembky assembly = Assembly.LoadFrom("DLL文件名+后缀名");
Type type = assembly.GetType("命名空间.类名");
object oReflection = Activator.CreateInstance(type);
//获取方法名
foreach(var method in type.GetMethods())
{
    //获取方法名
    Console.WriteLine(method.Name);
    //获取方法参数
    foreach(var parameter in method.GetParameters())
    {
        Console.WriteLine(parameter.Name+" "+parameter.ParameterType);
    }
}
MethodInfo methodInfo = type.GetMethod("方法名",BindingFlags.Instance|BindingFlags.NonPublic);
methodInfo.Invoke(oReflection,new object[]{参数});使用反射调用普通类里泛型方法
Assembky assembly = Assembly.LoadFrom("DLL文件名+后缀名");
Type type = assembly.GetType("命名空间.类名");
object oReflection = Activator.CreateInstance(type);
//获取要调用的方法
MethodInfo methodInfo = type.GetMethod("Test");
//确定方法的参数类型和个数
MethodInfo methodGeneric = methodInfo.MakeGenericMethod(new Type[]{typeof(int),typeof(string),typeof(double)});
//调用方法
methodGeneric.Invoke(oReflection,new object[]{传入对应类型的参数});使用反射调用泛型类当中的泛型方法
Assembky assembly = Assembly.LoadFrom("DLL文件名+后缀名");
Type type = assembly.GetType("命名空间.类名+`+类型个数");
//确定泛型的参数类型
Type typeNew = type.MakeGenericType(new Type[]{typeof(参数类型)...});
object oReflection = Activator.CreateInstance(type);
//获取调用方法
MethodInfo methodInfo = type.GetMethod("方法名");
//确定方法的参数类型
MethodInfo methodInfoNew = methodInfo.MakeGenericMethod(new Type[]{typeof(参数类型)...});
methodInfoNew.Invoke(oReflection,new object[]{传入对应类型参数});使用反射操作属性和字段等成员
Assembly assembly = Assembly.LoadForm("DLL文件名+后缀名");
Type type = assembly.Gettype("命名空间+类名");
object oStudent = Activator.Createlnstance(type);//创建对象
//方式一
foreach(var prop in type.GetProperties())
{
    //获取属性的类型  名字  数值
    Console.WriteLine($"{prop.PropertyType}+{prop.Name}={prop.GetValue(类对象)}");
    if(prop.Name.Equals("属性名"))
    {
        prop.SetValue(对象,设置的参数);
    }
    
}
//方式二
//使用PropertyInfo
PropertyInfo[] propertyInfos = type.GetProperties();//查找所有属性
PropertyInfo propertyInfo = type.GetProperty("属性名"); 
                    
                
 
                
            
         浙公网安备 33010602011771号
浙公网安备 33010602011771号