跳转至

Reflection —— 反射

一时反射一时爽,一直反射一直爽

获取属性信息

 Type compareInfoType = typeof(CompareItem);
 PropertyInfo[] properties = compareInfoType.GetProperties();

随后可通过properties[i].Name获取属性名,properties[i].GetValue(obj)获取属性值(其中obj)是具体的实例

创建对象

通过反射创建对象,需要获取构造函数信息,并调用构造函数的Invoke方法,传入参数,即可创建对象

下面这个例子中,CreateInstance方法要通过dataRow中的数据,使用反射创建T类型的对象

 public static T CreateInstance<T>(DataRow dataRow)
 {
     Type type = typeof(T);
     ConstructorInfo constructorInfo = type.GetConstructor(new Type[] { });
     if(constructorInfo != null)
     {
         //调用类的无参构造函数创建对象
         T instance = (T)constructorInfo.Invoke(new object[] { });
         PropertyInfo[] properties = type.GetProperties();
         foreach(PropertyInfo property in properties)
         {
             if (dataRow.Table.Columns.Contains(property.Name) 
                 && dataRow.Table.Columns[property.Name].DataType == property.PropertyType)
             {
                 property.SetValue(instance, dataRow[property.Name]);
             }
         }
         return instance;
     }
     return default(T);
 }

如果是有参构造函数,则将type.GetConstructor(new Type[] { })中的参数类型换成构造函数的参数类型即可 如:

public class ExampleClass
{
    public int Id { get; set; }
    public string Name { get; set; }

    // 有参构造函数
    public ExampleClass(int id, string name)
    {
        Id = id;
        Name = name;
    }
}

可通过以下代码获取有参构造函数信息

ConstructorInfo constructorInfo = type.GetConstructor(new Type[] { typeof(int), typeof(string) });

如果想要调用有参但有默认值的构造方法时,可以使用Type.Missing在Invoke时占位

public class MyClass
{
    // 带有默认参数的构造方法
    public MyClass(int requiredParam, string optionalParam = "default", bool flag = true)
    {
        Console.WriteLine($"构造方法被调用: requiredParam={requiredParam}, optionalParam={optionalParam}, flag={flag}");
    }
}

public class Program
{
    public static void Main()
    {
        // 获取类型信息
        Type type = typeof(MyClass);

        // 定义参数类型数组(包含默认参数)
        Type[] paramTypes = new Type[] { typeof(int), typeof(string), typeof(bool) };

        // 获取构造函数信息
        ConstructorInfo constructor = type.GetConstructor(
            BindingFlags.Public | BindingFlags.Instance,
            binder: null,
            types: paramTypes,
            modifiers: null
        );

        if (constructor != null)
        {
            // 调用构造函数,使用 Type.Missing 表示使用默认值+++++++
            object instance = constructor.Invoke(new object[] { 42, Type.Missing, Type.Missing });
            Console.WriteLine("对象创建成功!");
        }
        else
        {
            Console.WriteLine("未找到匹配的构造函数!");
        }
    }

反射访问私有字段

虽然说私有变量不能直接访问,但是通过反射,可以访问私有属性

//示例类
public class MyClass
{
    public int PublicField;
    private int PrivateField;
    public static int PublicStaticField;
    private static int PrivateStaticField;
}
通过反射访问私有字段,要指定搜索条件BindingFlags.NonPublic,如果不指定BindingFlags.Instance的话,只会检索私有的静态字段 如:

    // 获取所有非公有字段(不包括实例字段)
    FieldInfo[] nonPublicFields = myType.GetFields(BindingFlags.NonPublic);
    //效果和上面一样
    FieldInfo[] nonPublicFields = myType.GetFields(BindingFlags.NonPublic| BindingFlags.Static);

结果:

非公有字段:
PrivateStaticField

如果要同时获取实例字段,则要指定BindingFlags.Instance

    FieldInfo[] nonPublicFields = myType.GetFields(BindingFlags.NonPublic| BindingFlags.Static|BindingFlags.Instance);

而如果不指定搜索条件的话,则会同时检索到公有的实例和静态字段,私有的不会被检索出来

至于其他关于方法的反射,等用到的时候再记录 👽