最全C# Reflection反射机制

一、反射

什么是反射

.Net的应用程序如下部分组成:‘程序集(Assembly)’、‘模块(Module)’、‘类型(class)’组成;

反射提供一种编程的方式,让程序员可以在程序运行期获得这几个组成部分的相关信息;

Type类可以获得对象的类型信息:方法、构造器、属性、字段;.

这些都包含在System.Reflection命名空间下;

程序集(assembly)

.dll编译好的库,里面可能有多个命名空间;.exe可执行文件;这两个种都是程序集;

模块(Module)

C#中没有模块,但提供了类似的功能:静态变量;

在C#中模块的另外一个含义是:
一种可加载单元,它可以包含类型声明和类型实现。模块包含的信息足以使公共语言运行库在模块加载时找到所有的实现位。模块的格式是 Windows 可移植可执行 (PE) 文件格式的扩展。在部署时,模块总是包含在程序集中;

个人觉得C#中没有太注重模块,有另一个概念,命名空间;将多个一类功能的类组合在同一命名空间下;

作用

运行期得到类型信息,修改属性或调用方法;

提高可扩展性;

二、反射方法

测试类,包含有参无参数构造;属性,方法,字段;

//测试类class Person{    //构造    public Person(){}    public Person(string name)    {        this.name = name;    }
    //字段    string name;    int age;
    //属性    public string Name{        get{            return name;        }        set{            name = value;        }    }
    //方法    public void SetName(string input)    {        name = input;    }}

获取字段

通过Type类可获得以下信息;

Person p = new PersonType t = typeof(p)
//获取所有字段FieldInfo[] fieldInfos = type.GetFields();//获取单个字段FieldInfo fieldInfo = type.GetFields("name");
fieldInfo.SetValue(p,"perilla")

获取属性

Person p = new PersonType t = typeof(p)
//获取所有属性PropertyInfo[] propertyInfos = type.GetProperties();//获取单个属性PropertyInfo propertyInfo = type.GetProperty("Name");
propertyInfo.SetValue(p,"perilla")

获取方法

Person p = new PersonType t = typeof(p)
//获取所有属性MethodInfo[] methodInfos = type.GetMethods();//获取单个属性MethodInfo methodInfo = type.GetMethod("SetName");
methodInfo.Invoke(p,"Perilla")

动态创建

Person p = new PersonType t = typeof(p)object obj = System.Activator.CreateInstance(t,"Perilla")
//也可以获取构造通过构造创建

三、反射工具类

public class ReflectTool{    #region 成员读写    /// <summary>    /// 通过参数列表,填充实体类型    /// </summary>    /// <param name="model">实体对象</param>    /// <param name="objs">数据只读器</param>    public static void FillInstanceValue(object model, params object[] objs)    {        Type type = model.GetType();        PropertyInfo[] properties = type.GetProperties();        for (int i = 0; i < objs.Length; i++)        {            properties[i].SetValue(model, objs[i], null);              }    }
    /// <summary>    /// 通过kv参数表,填充实体类型    /// </summary>    /// <param name="model">实体对象</param>    /// <param name="objs">数据只读器</param>    public static void FillInstanceValue(object model, Dictionary<string,object> paramDic)    {        Type type = model.GetType();        PropertyInfo[] properties = type.GetProperties();        for (int i = 0; i < paramDic.Count; i++)        {            if (paramDic.ContainsKey(properties[i].Name))            {                properties[i].SetValue(model, paramDic[properties[i].Name]);            }        }    }
    public static void FillInstanceField(object model, Dictionary<string, object> paramDic)    {        Type type = model.GetType();        FieldInfo[] fieldInfos = type.GetFields();        for (int i = 0; i < paramDic.Count; i++)        {            if (paramDic.ContainsKey(fieldInfos[i].Name))            {                Type it = fieldInfos[i].GetType();                fieldInfos[i].SetValue(model, paramDic[fieldInfos[i].Name]);            }        }    }

    /// <summary>    /// 获取实体相关属性的值    /// </summary>    /// <param name="obj"></param>    /// <param name="propertyName"></param>    /// <returns></returns>    public static object GetInstanceValue(object obj, string propertyName)    {        object objRet = null;        if (!string.IsNullOrEmpty(propertyName))        {            PropertyDescriptor descriptor = TypeDescriptor.GetProperties(obj).Find(propertyName, true);            if (descriptor != null)            {                objRet = descriptor.GetValue(obj);            }        }        return objRet;    }    #endregion
    #region 方法调用    /// 直接调用内部对象的方法/函数或获取属性(支持重载调用)    /// <param name="refType">目标数据类型</param>    /// <param name="funName">函数名称,区分大小写。</param>    /// <param name="objInitial">如果调用属性,则为相关对象的初始化数据(带参数构造,只能调用Get),否则为Null。</param>    /// <param name="funParams">函数参数信息</param>    public static object InvokeMethodOrGetProperty(Type refType, string funName, object[] objInitial, params object[] funParams)    {        MemberInfo[] mis = refType.GetMember(funName);        if (mis.Length < 1)        {            throw new InvalidProgramException(string.Concat("函数/方法 [", funName, "] 在指定类型(", refType.ToString(), ")中不存在!"));        }        else        {            MethodInfo targetMethod = null;            StringBuilder pb = new StringBuilder();            foreach (MemberInfo mi in mis)            {                if (mi.MemberType != MemberTypes.Method)                {                    if (mi.MemberType == MemberTypes.Property)                    {                        #region 调用属性方法Get                        targetMethod = ((PropertyInfo)mi).GetGetMethod();                        break;                        #endregion                    }                    else                    {                        throw new InvalidProgramException(string.Concat("[", funName, "] 不是有效的函数/属性方法!"));                    }                }                else                {                    #region 检查函数参数和数据类型 绑定正确的函数到目标调用                    bool validParamsLen = false, validParamsType = false;
                    MethodInfo curMethod = (MethodInfo)mi;                    ParameterInfo[] pis = curMethod.GetParameters();                    if (pis.Length == funParams.Length)                    {                        validParamsLen = true;
                        pb = new StringBuilder();                        bool paramFlag = true;                        int paramIdx = 0;
                        #region 检查数据类型 设置validParamsType是否有效                        foreach (ParameterInfo pi in pis)                        {                            pb.AppendFormat("Parameter {0}: Type={1}, Name={2}\n", paramIdx, pi.ParameterType, pi.Name);
                            //不对Null和接受Object类型的参数检查                            if (funParams[paramIdx] != null && pi.ParameterType != typeof(object) &&                                 (pi.ParameterType != funParams[paramIdx].GetType()))                            {                                #region 检查类型是否兼容                                try                                {                                    //TODO====这里有问题,实例是子类对象,参数是父类,父父类接口,无法转化,但是确实是参数;                                    funParams[paramIdx] = Convert.ChangeType(funParams[paramIdx], pi.ParameterType);                                }                                catch (Exception)                                {                                    paramFlag = false;                                }                                #endregion                                //break;                            }                            ++paramIdx;                        }                        #endregion
                        if (paramFlag == true)                        {                            validParamsType = true;                        }                        else                        {                            continue;                        }
                        if (validParamsLen && validParamsType)                        {                            targetMethod = curMethod;                            break;                        }                    }                    #endregion                }            }
            if (targetMethod != null)            {                object objReturn = null;                #region 兼顾效率和兼容重载函数调用                try                {                    object objInstance = System.Activator.CreateInstance(refType, objInitial);                    objReturn = targetMethod.Invoke(objInstance, BindingFlags.InvokeMethod, Type.DefaultBinder, funParams,                        System.Globalization.CultureInfo.InvariantCulture);                }                catch (Exception)                {                    objReturn = refType.InvokeMember(funName, BindingFlags.InvokeMethod, Type.DefaultBinder, null, funParams);                }                #endregion                return objReturn;            }            else            {                throw new InvalidProgramException(string.Concat("函数/方法 [", refType.ToString(), ".", funName,                    "(args ...) ] 参数长度和数据类型不正确!\n 引用参数信息参考:\n",                    pb.ToString()));            }        }
    }
    /// 调用相关实体类型的函数方法    /// <param name="refType">实体类型</param>    /// <param name="funName">函数名称</param>    /// <param name="funParams">函数参数列表</param>    public static object InvokeFunction(Type refType, string funName, params object[] funParams)    {        return InvokeMethodOrGetProperty(refType, funName, null, funParams);    }    #endregion
    #region 创建实例
    //通过Type创建实例,返回Object    public static object CreateInstance(Type refType, params object[] objInitial)     {        object res = System.Activator.CreateInstance(refType, objInitial);
        return res;    }
    //通过泛型T创建实例,并返回T    public static T CreateInstance<T>(params object[] objInitial) where T : new()    {        Type refType = typeof(T);        object res = System.Activator.CreateInstance(refType, objInitial);
        if (res == null)        {            Debug.LogError("Reflect create T is null");        }
        return (T)res;        }
    #endregion}

调用测试

public class Test{    public Test() { }    public Test(string name) { this.name = name; }
    private string name;
    public string Name {        get {            //Debug.Log($"PorperityGet:{name}");            return name;        }        set {            name = value;            //Debug.Log($"PorperitySet:{name}");        }    }
    public void Func1()    {        Debug.Log("Test.Func1");    }
    public void Func2(int para1)    {        Debug.Log($"Test.Func1:{para1}");    }
    public void Func3(string para1,int para2)    {        Debug.Log($"Test.Func1:{para1},{para2}");    }}
void Start(){  Test obj = new Test();    Type t = obj.GetType();    ReflectTool.InvokeFunction(t, "Func1");    ReflectTool.InvokeFunction(t, "Func2", 5);    ReflectTool.InvokeFunction(t, "Func3", "perilla", 25);
    object[] objs = new object[1];    objs[0] = "perilla";    ReflectTool.InvokeMethodOrGetProperty(t, "Name", objs);    ReflectTool.InvokeFunction(t, "Name");    obj.Name = "hhahah";    ReflectTool.FillInstanceValue(obj, "QAQ");    Dictionary<string, object> dic = new Dictionary<string, object>();    dic["Name"] = "QWQ";    ReflectTool.FillInstanceValue(obj, dic);    Debug.Log(ReflectTool.GetInstanceValue(obj, "Name"));
    obj = ReflectTool.CreateInstance(t, "skylar") as Test;    Debug.Log(obj.Name);
    obj = ReflectTool.CreateInstance<Test>("Rebort");    Debug.Log(obj.Name);
    string str = "    adfas dfaf ffff dsawee    dff   ";    str = System.Text.RegularExpressions.Regex.Replace(str, @"\s", "");    Debug.Log(str);    Config config = ConfigTool.GetConfig<Config>(Application.dataPath+"/Config.cfg");    Debug.Log($"ServerAddr:{config.ServerIp};Port:{config.Port}"); }

最全C# Reflection反射机制

四、特性

C# 反射的特性包括:
1、动态加载和查找类型:反射允许程序在运行时动态地加载程序集,并查找和获取其中的类型信息。
2、访问和操作类型信息:通过反射可以访问和操作类型的成员信息,如属性、字段、方法等,以及获取它们的值或者调用它们的方法。
3、创建类型实例:反射可以动态地创建一个类的实例,并调用其构造函数。
4、获取和设置属性和字段的值:反射可以获取或设置类的属性或字段的值。
5、动态调用方法:反射可以动态地调用类的方法,并传递参数。
6、可以在程序运行时动态地加载程序集:反射使得程序能够动态地加载程序集,从而提供更大的灵活性和可扩展性。
7、可以进行代码注入:通过反射可以动态地修改程序的行为,例如可以实现代码注入等高级特性。
8、可以进行代码生成:反射可以根据程序集中的元数据生成新的代码。