C#反射

本文介绍了如何使用C#的Type类进行反射操作,包括获取类的属性、字段,并通过GetValue和SetValue方法进行读写操作。示例代码展示了如何访问静态和实例字段,并对不同访问级别的字段进行操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

ClassType  ClassName=new ClassType();//一个实例化的类,类型是ClassType  ,类名为ClassName
Type type = ClassName.GetType();       //得到Type类型
FieldInfo[] info = type.GetFields(); //得到字段数组
foreach (FieldInfo i in info ) //遍历此数组
{
     object obj = i.GetValue(ClassName); //变量值
     string name = i.Name; //变量名


Type 类

C#中通过 Type类可以访问任意数据类型信息。
1.获取给定类型的Type引用有3种方式:
   a.使用typeof运算符,如Type t = typeof(int);
   b.使用GetType()方法,如int i;Type t = i.GetType();
   c.使用 Type类的静态方法GetType(),如Type t =Type.GetType("System.Double");
2.Type的属性:
   Name:数据类型名;
   FullName:数据类型的完全限定名,包括命名空间;
   Namespace:数据类型的命名空间;
   BaseType:直接基本类型;
   UnderlyingSystemType:映射类型;
3.Type的方法:
   GetMethod():返回一个方法的信息;
   GetMethods():返回所有方法的信息。


PropertyInfo[] ps = type.GetProperties();//得到属性数组

PropertyInfo propertyInfo = type.GetProperty("Property1"); //获取指定名称的属性

propertyInfo.GetValue(ClassName, null); //获取属性值

propertyInfo.SetValue(ClassName, value, null); //给对应属性赋值



Type.GetFields();//只获取public字段,静态public字段和实例public字段都获取

Type.GetFields(BindingFlags);//获取BindingFlags标记的字段

BindingFlags//由于BindingFlags的枚举值按位定义,如果使用多于两个BindingFlags可以用位运算|

BindingFlags.Static 和BindingFlags.Instance中至少要有一个

枚举值 成员名称 描述
由 XNA Framework 提供支持   512 CreateInstance 指定“反射”应该创建指定类型的实例。 调用与给定参数匹配的构造函数。 忽略提供的成员名。 如果未指定查找类型,将应用 (Instance |Public)。 调用类型初始值设定项是不可能的。
由 XNA Framework 提供支持受 可移植类库 支持  2 DeclaredOnly 指定只应考虑在所提供类型的层次结构级别上声明的成员。 不考虑继承成员。
由 XNA Framework 提供支持   0 Default 不指定绑定标志。
由 XNA Framework 提供支持受 可移植类库 支持 65536 ExactBinding 指定提供参数的类型必须与对应形参的类型完全匹配。 如果调用方提供一个非空 Binder 对象,则“反射”将引发异常,因为这意味着调用方正在提供的 BindToXXX 实现将选取适当的方法。

“反射”建立通用类型系统的可访问规则模型。 例如,如果调用方在相同的程序集内,则它不需要内部成员的特殊权限。 否则,调用方需要ReflectionPermission 这与保护成员、私有成员等成员的查找是一致的。

一般原则是 ChangeType 应该只执行拓宽强制,后者从不丢失数据。 扩展强制的一个例子是将 32 位有符号整数值强制为 64 位有符号整数值。这与窄缩强制不同,后者可能丢失数据。 窄缩强制的一个例子是将 64 位有符号整数强制为 32 位有符号整数。

默认联编程序忽略此标志,而自定义联编程序可以实现此标志的语义。

由 XNA Framework 提供支持受 可移植类库 支持  64 FlattenHierarchy 指定应返回层次结构上的公共静态成员和受保护的静态成员。 不返回继承类中的私有静态成员。 静态成员包括字段、方法、事件和属性。 不返回嵌套类型。
由 XNA Framework 提供支持   1024 GetField 指定应返回指定字段的值。
由 XNA Framework 提供支持   4096 GetProperty 指定应返回指定属性的值。
由 XNA Framework 提供支持受 可移植类库 支持  1 IgnoreCase 指定当绑定时不应考虑成员名的大小写。
由 XNA Framework 提供支持 16777216 IgnoreReturn 在 COM 互操作中用于指定可以忽略成员的返回值。
由 XNA Framework 提供支持受 可移植类库 支持  4 Instance 指定实例成员将包括在搜索中。
由 XNA Framework 提供支持   256 InvokeMethod 指定要调用一个方法。 它不能是构造函数或类型初始值设定项。
由 XNA Framework 提供支持受 可移植类库 支持  32 NonPublic 指定非公共成员将包括在搜索中。包括internal,protected,private
由 XNA Framework 提供支持受 可移植类库 支持  262144 OptionalParamBinding 返回其参数计数与提供参数的数目匹配的成员集。 此绑定标志用于所带参数具有默认值的方法和带变量参数 (varargs) 的方法。 此标志应只与Type.InvokeMember 一起使用。

具有默认值的参数仅用在省略尾部参数的调用中。 它们必须是最后的参数。

由 XNA Framework 提供支持受 可移植类库 支持  16 Public 指定公共成员将包括在搜索中。只有public
由 XNA Framework 提供支持   16384 PutDispProperty 指定应调用 COM 对象的 PROPPUT 成员。 PROPPUT 指定使用值的属性设置函数。 如果属性同时具有 PROPPUT 和 PROPPUTREF,而且需要区分调用哪一个,请使用 PutDispProperty
由 XNA Framework 提供支持   32768 PutRefDispProperty 指定应调用 COM 对象的 PROPPUTREF 成员。 PROPPUTREF 指定使用引用而不是值的属性设置函数。 如果属性同时具有 PROPPUT 和PROPPUTREF,而且需要区分调用哪一个,请使用PutRefDispProperty
由 XNA Framework 提供支持   2048 SetField 指定应设置指定字段的值。
由 XNA Framework 提供支持   8192 SetProperty 指定应设置指定属性的值。 对于 COM 属性,指定此绑定标志与指定PutDispProperty 和 PutRefDispProperty 是等效的。
由 XNA Framework 提供支持受 可移植类库 支持  8 Static 指定静态成员将包括在搜索中。
由 XNA Framework 提供支持   131072 SuppressChangeType 未实现。

FieldInfo.SetValue(Object obj,Object value);

参数
obj
类型: System.Object
将设置其字段值的对象。
value
类型: System.Object
分配给字段的值。
当obj是null的时候只能对静态字段赋值,对非静态字段赋值会报错

当obj是实例的时候可以对任意字段赋值

例子

using UnityEngine;
using System.Collections;
using System;
using System.Reflection;


public class FanSheText : MonoBehaviour {
void Start () {
        FanShe myInstance = new FanShe();
        Type t = typeof(FanShe);
        FieldInfo[] sharedFields = t.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance);
        Debug.LogError("静态开始");
        foreach (FieldInfo f in sharedFields)
        {
            try
            {
                string newValue = f.GetValue(null) + " -存储成功-";
                
                f.SetValue(null, newValue);


                print(String.Format("The value of Shared field {0} is: {1}\n",f.Name,f.GetValue(null)));
            }
            catch
            {
                print(String.Format("The value of Shared field {0} is not accessible.\n", f.Name));
            }
        }
        Debug.LogError("静态结束");


        FieldInfo[] instanceFields = t.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance);
        Debug.LogError("实例开始");
        foreach (FieldInfo f in instanceFields)
        {
            try
            {
                // Append a marker to the old value.
                string newValue = f.GetValue(myInstance) + " -存储成功-";


                f.SetValue(myInstance, newValue);


                print(String.Format("The value of insktance field {0} is: {1}\n", f.Name, f.GetValue(myInstance)));
            }
            catch
            {


                print(String.Format("The value of instance field {0} is not accessible.\n", f.Name));
            }
        }
        Debug.LogError("实例结束");
}
}


public class FanShe
{
    public static string SA = "A public shared field.";
    internal static string SB = "A friend shared field.";
    protected static string SC = "A protected shared field.";
    private static string SD = "A private shared field.";
    private static string se = "";
    public static string SE
    {
        get
        {
            return se;
        }
        set
        {
            se = value;
        }
    }


    public string A = "A public instance field.";
    internal string B = "A friend instance field.";
    protected string C = "A protected instance field.";
    private string D = "A private instance field.";
    private string e = "";
    public string E
    {
        get
        {
            return e;
        }
        set
        {
            e = value;
        }
    }
}


<think>好的,用户现在问的是关于C#反射的介绍。首先,我需要回忆一下反射的基本概念。反射C#中是一个强大的功能,允许程序在运行时获取型信息并动态调用方法或访问属性。可能用户是刚开始学习C#,或者在做一些需要动态处理型的项目,比如插件系统或者序列化工具。 接下来,用户的需求可能不仅仅是了解反射是什么,而是想知道它的实际应用场景、常见用法以及需要注意的问题。用户可能在使用反射时遇到了性能问题或者安全问题,所以需要强调这些方面。同时,用户可能希望看到具体的代码示例,这样能更好地理解如何操作。 然后,我需要考虑如何组织内容。首先定义反射,说明其作用。然后分点介绍常见用途,比如型检查、动态创建对象、调用方法、访问属性字段等。每个用途最好配上简单的代码示例,让用户一目了然。接着,要提到反射的高级应用,比如特性处理和动态加载程序集,这些都是实际开发中常用的场景。 然后,必须提到反射的优缺点。用户可能知道反射的强大,但不知道其性能开销和安全隐患,这部分需要详细说明,给出优化建议,比如缓存Type对象或使用dynamic关键字。此外,还要提到代码可读性和维护性问题,帮助用户全面了解反射的适用场景。 最后,总结部分要强调反射的灵活性和风险,给出最佳实践建议,比如在必要时使用,并考虑替代方案。这样用户不仅能了解反射,还能在实际项目中合理应用,避免滥用。 现在需要检查是否有遗漏的重要点,比如安全性中的部分信任环境,或者代码示例的正确性。确保示例代码简洁,没有错误。同时,保持语言口语化,避免过于技术化的术语,让初学者也能理解。另外,用户之前的提问是关于ERP多线程的问题,可能用户对性能方面比较敏感,所以反射的性能问题需要特别强调。</think>### C# 反射(Reflection)详解 反射(Reflection)是 C# 中一项强大的功能,允许程序在 **运行时** 动态获取型信息、访问或操作对象成员(属性、方法、字段等),甚至动态创建型实例。它是实现灵活性和动态行为的核心机制,但需谨慎使用以避免性能和安全问题。 --- #### **1. 反射的核心用途** - **运行时型检查**:获取型元数据(如名、基、接口、方法列表等)。 - **动态创建对象**:根据型名称实例化对象。 - **调用未知方法**:动态执行中未在编译期绑定的方法。 - **访问私有成员**:突破访问权限限制(需注意安全性)。 - **插件系统开发**:动态加载外部程序集(DLL)并扩展功能。 --- #### **2. 反射的基本操作** ##### **2.1 获取型信息** 通过 `Type` 表示型的元数据,获取方式: ```csharp // 方式1:通过对象获取 Type type1 = obj.GetType(); // 方式2:通过型名称获取 Type type2 = Type.GetType("System.String"); // 方式3:通过 typeof 运算符 Type type3 = typeof(string); ``` ##### **2.2 动态创建对象** ```csharp Type type = Type.GetType("MyNamespace.MyClass"); object instance = Activator.CreateInstance(type); // 调用无参构造函数 // 调用含参构造函数 object instanceWithArgs = Activator.CreateInstance(type, new object[] { "参数1", 100 }); ``` ##### **2.3 调用方法** ```csharp Type type = instance.GetType(); MethodInfo method = type.GetMethod("MethodName"); method.Invoke(instance, new object[] { 参数1, 参数2 }); // 调用实例方法 // 调用静态方法 MethodInfo staticMethod = type.GetMethod("StaticMethod"); staticMethod.Invoke(null, new object[] { 参数 }); ``` ##### **2.4 访问属性/字段** ```csharp // 获取或设置属性 PropertyInfo prop = type.GetProperty("PropertyName"); object value = prop.GetValue(instance); // 获取值 prop.SetValue(instance, "新值"); // 设置值 // 访问私有字段(需指定 BindingFlags) FieldInfo field = type.GetField("_privateField", BindingFlags.NonPublic | BindingFlags.Instance); object fieldValue = field.GetValue(instance); ``` --- #### **3. 反射的高级应用** ##### **3.1 特性(Attribute)处理** 通过反射读取或成员上的自定义特性: ```csharp Type type = typeof(MyClass); object[] attrs = type.GetCustomAttributes(typeof(MyAttribute), false); if (attrs.Length > 0) { MyAttribute attr = (MyAttribute)attrs[0]; Console.WriteLine(attr.Description); } ``` ##### **3.2 动态加载程序集** ```csharp // 加载 DLL 文件 Assembly assembly = Assembly.LoadFrom("MyPlugin.dll"); // 遍历程序集中的所有型 foreach (Type t in assembly.GetTypes()) { if (t.IsClass && !t.IsAbstract) { object plugin = Activator.CreateInstance(t); // 调用插件初始化方法 } } ``` --- #### **4. 反射的优缺点** | **优点** | **缺点** | |------------------------------|---------------------------------------| | 灵活性强,支持动态扩展 | 性能开销大(比直接调用慢 100~1000 倍) | | 实现插件化架构 | 代码可读性差,调试困难 | | 可绕过访问权限(慎用) | 可能引发安全问题(如访问私有成员) | --- #### **5. 性能优化建议** - **缓存 Type 对象**:避免重复调用 `GetType()` 或 `typeof()`。 - **使用 `dynamic` 关键字**:对已知型动态调用时,`dynamic` 比反射更快。 - **预编译表达式树**:通过 `Expression` 生成委托,替代反射调用。 ```csharp var method = typeof(MyClass).GetMethod("MyMethod"); var instance = Expression.Parameter(typeof(MyClass), "obj"); var call = Expression.Call(instance, method); var lambda = Expression.Lambda<Action<MyClass>>(call, instance).Compile(); lambda(myInstance); // 快速调用 ``` --- #### **6. 典型应用场景** - **依赖注入框架**:自动解析构造函数参数。 - **ORM 框架**:将数据库字段映射到实体属性。 - **序列化/序列化**:动态处理 JSON/XML 数据。 - **单元测试工具**:动态执行测试方法。 --- ### **总结** 反射C# 中实现动态编程的利器,但需权衡其灵活性与性能损耗。**在以下场景优先考虑反射**: - 需要动态加载外部代码(如插件)。 - 无法在编译期确定型(如配置文件驱动)。 - 开发通用框架或工具库。 **避免滥用**:在性能敏感场景(如循环内)或安全关键代码中谨慎使用。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值