C# 反射详解

1. 反射概述

反射(Reflection)是.NET框架提供的强大功能,允许在运行时:

  • 检查程序集、模块和类型的元数据

  • 动态创建类型实例

  • 动态调用方法和访问属性/字段

  • 在运行时创建新类型(动态代码生成)

核心命名空间System.Reflection

2. 获取类型信息

2.1 获取 Type 对象

csharp

复制代码
// 方式1:使用 typeof 运算符
Type type1 = typeof(string);

// 方式2:使用 GetType() 方法
string str = "Hello";
Type type2 = str.GetType();

// 方式3:使用 Type.GetType() 静态方法
Type type3 = Type.GetType("System.String");

// 方式4:获取程序集中的类型
Assembly assembly = Assembly.Load("mscorlib");
Type type4 = assembly.GetType("System.String");

2.2 Type 类的常用属性

csharp

复制代码
Type type = typeof(MyClass);

// 基本信息
string name = type.Name;           // 类型名
string fullName = type.FullName;   // 完全限定名
bool isClass = type.IsClass;       // 是否是类
bool isInterface = type.IsInterface; // 是否是接口
bool isAbstract = type.IsAbstract; // 是否是抽象类
bool isSealed = type.IsSealed;     // 是否是密封类

// 类型关系
Type baseType = type.BaseType;     // 基类
bool isSubclass = type.IsSubclassOf(typeof(ParentClass)); // 是否继承自某类
bool isInstanceOfType = type.IsInstanceOfType(obj); // 对象是否是该类型实例

3. 反射核心操作

3.1 获取成员信息

csharp

复制代码
public class Person
{
    public string Name { get; set; }
    private int age;
    public void SayHello() { }
    public static void StaticMethod() { }
}

Type type = typeof(Person);

// 获取所有公共方法
MethodInfo[] methods = type.GetMethods();

// 获取特定方法
MethodInfo method = type.GetMethod("SayHello");

// 获取所有公共属性
PropertyInfo[] properties = type.GetProperties();

// 获取特定属性
PropertyInfo property = type.GetProperty("Name");

// 获取所有字段(包括私有)
FieldInfo[] fields = type.GetFields(BindingFlags.NonPublic | BindingFlags.Instance);

// 获取构造函数
ConstructorInfo[] constructors = type.GetConstructors();
ConstructorInfo ctor = type.GetConstructor(new Type[] { typeof(string) });

3.2 创建实例

csharp

复制代码
// 方式1:使用 Activator.CreateInstance
object obj1 = Activator.CreateInstance(typeof(Person));

// 方式2:带参数的构造函数
object obj2 = Activator.CreateInstance(typeof(Person), "John");

// 方式3:使用 ConstructorInfo
ConstructorInfo ctor = typeof(Person).GetConstructor(new Type[] { typeof(string) });
object obj3 = ctor.Invoke(new object[] { "Alice" });

// 方式4:创建泛型实例
Type genericListType = typeof(List<>);
Type specificListType = genericListType.MakeGenericType(typeof(int));
object list = Activator.CreateInstance(specificListType);

3.3 调用方法和属性

csharp

复制代码
// 创建实例
object person = Activator.CreateInstance(typeof(Person));

// 设置属性值
PropertyInfo nameProp = typeof(Person).GetProperty("Name");
nameProp.SetValue(person, "Tom");

// 获取属性值
string name = (string)nameProp.GetValue(person);

// 调用方法
MethodInfo sayHelloMethod = typeof(Person).GetMethod("SayHello");
sayHelloMethod.Invoke(person, null);  // 无参数方法

// 调用私有方法(需要指定 BindingFlags)
MethodInfo privateMethod = typeof(Person).GetMethod("PrivateMethod", 
    BindingFlags.NonPublic | BindingFlags.Instance);
privateMethod.Invoke(person, null);

3.4 字段操作

csharp

复制代码
// 设置私有字段
FieldInfo ageField = typeof(Person).GetField("age", 
    BindingFlags.NonPublic | BindingFlags.Instance);
ageField.SetValue(person, 25);

// 获取字段值
int age = (int)ageField.GetValue(person);

4. 程序集操作

csharp

复制代码
// 加载程序集
Assembly assembly1 = Assembly.Load("System.Data");  // 从GAC加载
Assembly assembly2 = Assembly.LoadFrom(@"C:\MyAssembly.dll");  // 从文件加载
Assembly assembly3 = Assembly.GetExecutingAssembly();  // 当前执行程序集

// 获取程序集信息
string name = assembly1.FullName;
AssemblyName assemblyName = assembly1.GetName();

// 获取程序集中所有类型
Type[] allTypes = assembly1.GetTypes();

// 获取特定类型
Type specificType = assembly1.GetType("System.Data.DataTable");

// 获取程序集中的资源
Stream resourceStream = assembly1.GetManifestResourceStream("ResourceName");

5. 特性(Attribute)与反射

csharp

复制代码
// 自定义特性
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public class MyAttribute : Attribute
{
    public string Description { get; set; }
    public MyAttribute(string description) => Description = description;
}

// 应用特性
[MyAttribute("这是一个测试类")]
public class TestClass
{
    [MyAttribute("这是一个测试方法")]
    public void TestMethod() { }
}

// 反射获取特性
Type type = typeof(TestClass);

// 获取类上的特性
MyAttribute classAttr = (MyAttribute)Attribute.GetCustomAttribute(type, typeof(MyAttribute));

// 获取方法上的特性
MethodInfo method = type.GetMethod("TestMethod");
MyAttribute methodAttr = (MyAttribute)Attribute.GetCustomAttribute(method, typeof(MyAttribute));

// 获取所有特性
object[] attributes = type.GetCustomAttributes(true);

6. 泛型反射

csharp

复制代码
// 获取泛型类型信息
Type listType = typeof(List<>);
Console.WriteLine($"IsGenericType: {listType.IsGenericType}");
Console.WriteLine($"IsGenericTypeDefinition: {listType.IsGenericTypeDefinition}");

// 创建泛型实例
Type specificListType = listType.MakeGenericType(typeof(int));
object intList = Activator.CreateInstance(specificListType);

// 获取泛型参数
Type[] genericArgs = specificListType.GetGenericArguments();  // 返回 int[]

// 检查泛型约束
Type parameterType = listType.GetGenericArguments()[0];
GenericParameterAttributes constraints = parameterType.GenericParameterAttributes;

7. 性能优化技巧

7.1 缓存反射对象

csharp

复制代码
public class ReflectionCache
{
    private static Dictionary<string, PropertyInfo> _propertyCache = new();
    
    public static PropertyInfo GetProperty(Type type, string propertyName)
    {
        string key = $"{type.FullName}.{propertyName}";
        
        if (!_propertyCache.TryGetValue(key, out PropertyInfo property))
        {
            property = type.GetProperty(propertyName);
            _propertyCache[key] = property;
        }
        
        return property;
    }
}

7.2 使用 Delegate.CreateDelegate

csharp

复制代码
// 传统反射调用
MethodInfo method = typeof(MyClass).GetMethod("MyMethod");
method.Invoke(instance, new object[] { param1, param2 });

// 优化:创建委托
MethodInfo method = typeof(MyClass).GetMethod("MyMethod");
var delegateMethod = (Action<MyClass, int, string>)Delegate.CreateDelegate(
    typeof(Action<MyClass, int, string>), method);
    
delegateMethod(instance, param1, param2);  // 性能接近直接调用

7.3 使用表达式树

csharp

复制代码
public static class PropertyAccessor
{
    public static Func<object, object> CreateGetPropertyDelegate(Type type, string propertyName)
    {
        var param = Expression.Parameter(typeof(object), "instance");
        var castParam = Expression.Convert(param, type);
        var property = Expression.Property(castParam, propertyName);
        var castResult = Expression.Convert(property, typeof(object));
        
        return Expression.Lambda<Func<object, object>>(castResult, param).Compile();
    }
}

// 使用
var getter = PropertyAccessor.CreateGetPropertyDelegate(typeof(Person), "Name");
object value = getter(personInstance);

8. 实际应用示例

8.1 对象映射器

csharp

复制代码
public class ObjectMapper
{
    public static TDestination Map<TSource, TDestination>(TSource source)
        where TDestination : new()
    {
        var destination = new TDestination();
        var sourceType = typeof(TSource);
        var destType = typeof(TDestination);
        
        var sourceProperties = sourceType.GetProperties();
        var destProperties = destType.GetProperties();
        
        foreach (var sourceProp in sourceProperties)
        {
            var destProp = destProperties.FirstOrDefault(p => 
                p.Name == sourceProp.Name && 
                p.PropertyType == sourceProp.PropertyType);
                
            if (destProp != null && destProp.CanWrite)
            {
                object value = sourceProp.GetValue(source);
                destProp.SetValue(destination, value);
            }
        }
        
        return destination;
    }
}

8.2 插件系统

csharp

复制代码
public class PluginManager
{
    public List<IPlugin> LoadPlugins(string pluginPath)
    {
        var plugins = new List<IPlugin>();
        
        foreach (var dllFile in Directory.GetFiles(pluginPath, "*.dll"))
        {
            Assembly assembly = Assembly.LoadFrom(dllFile);
            
            foreach (Type type in assembly.GetTypes())
            {
                if (typeof(IPlugin).IsAssignableFrom(type) && !type.IsAbstract)
                {
                    IPlugin plugin = (IPlugin)Activator.CreateInstance(type);
                    plugins.Add(plugin);
                }
            }
        }
        
        return plugins;
    }
}

9. 注意事项

  1. 性能问题:反射操作比直接代码调用慢,应避免在频繁调用的代码中使用

  2. 安全性:反射可以访问私有成员,破坏封装性

  3. 版本兼容性:使用反射时要注意类型和方法签名的变化

  4. 异常处理:反射操作可能抛出多种异常,需要妥善处理

10. .NET Core/.NET 5+ 中的变化

csharp

复制代码
// .NET Core 引入了新的反射API
// 传统方式(兼容性模式)
Type type = typeof(MyClass);
MethodInfo method = type.GetMethod("MyMethod");

// 新API(性能更好)
MethodInfo method2 = type.GetRuntimeMethod("MyMethod", new Type[] { });

// 获取所有实现的接口
IEnumerable<Type> interfaces = type.GetInterfaces();

// 获取所有成员(包括继承的)
IEnumerable<MemberInfo> members = type.GetRuntimeProperties();

总结

反射是C#中强大但需要谨慎使用的特性。正确的使用场景包括:

  • 插件系统开发

  • 序列化/反序列化

  • ORM框架

  • 动态代理

  • 测试框架

在实际开发中,应权衡反射带来的灵活性和性能开销,必要时使用缓存、委托或表达式树进行优化。

相关推荐
Scout-leaf8 小时前
WPF新手村教程(三)—— 路由事件
c#·wpf
代码匠心8 小时前
AI 自动编程:一句话设计高颜值博客
前端·ai·ai编程·claude
_AaronWong10 小时前
Electron 实现仿豆包划词取词功能:从 AI 生成到落地踩坑记
前端·javascript·vue.js
cxxcode10 小时前
I/O 多路复用:从浏览器到 Linux 内核
前端
用户54330814419410 小时前
AI 时代,前端逆向的门槛已经低到离谱 — 以 Upwork 为例
前端
JarvanMo10 小时前
Flutter 版本的 material_ui 已经上架 pub.dev 啦!快来抢先体验吧。
前端
恋猫de小郭10 小时前
AI 可以让 WIFI 实现监控室内人体位置和姿态,无需摄像头?
前端·人工智能·ai编程
哀木10 小时前
给自己整一个 claude code,解锁编程新姿势
前端
程序员鱼皮10 小时前
GitHub 关注突破 2w,我总结了 10 个涨星涨粉技巧!
前端·后端·github
UrbanJazzerati10 小时前
Vue3 父子组件通信完全指南
前端·面试