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. 注意事项
-
性能问题:反射操作比直接代码调用慢,应避免在频繁调用的代码中使用
-
安全性:反射可以访问私有成员,破坏封装性
-
版本兼容性:使用反射时要注意类型和方法签名的变化
-
异常处理:反射操作可能抛出多种异常,需要妥善处理
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框架
-
动态代理
-
测试框架
在实际开发中,应权衡反射带来的灵活性和性能开销,必要时使用缓存、委托或表达式树进行优化。