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框架

  • 动态代理

  • 测试框架

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

相关推荐
c#上位机4 小时前
halcon求区域交集——intersection
图像处理·人工智能·计算机视觉·c#·halcon
毕设源码-赖学姐4 小时前
【开题答辩全过程】以 基于Java的保定理工科研信息管理系统的设计与实现为例,包含答辩的问题和答案
java·开发语言
派大鑫wink4 小时前
从零到精通:Python 系统学习指南(附实战与资源)
开发语言·python
JIngJaneIL4 小时前
基于Java+ vue智慧医药系统(源码+数据库+文档)
java·开发语言·前端·数据库·vue.js·spring boot
吕了了5 小时前
87 Windows 系统安装的本质是什么?
运维·windows·电脑·系统
羸弱的穷酸书生5 小时前
国网 i1协议 python实现
开发语言·python
电子硬件笔记5 小时前
Python语言编程导论第三章 编写程序
开发语言·python·编辑器
布谷歌5 小时前
在java中实现c#的int.TryParse方法
java·开发语言·python·c#
cooldream20095 小时前
当代 C++ 的三大技术支柱:资源管理、泛型编程与模块化体系的成熟演进
开发语言·c++