C#预处理指令与反射机制深度解析

发布时间:2026/9/15 0:21:37
C#预处理指令与反射机制深度解析 1. C#预处理指令深度解析预处理指令是C#中一个强大但常被忽视的功能它允许开发者在编译阶段控制代码的编译行为。与C/C不同C#的预处理指令功能更为有限但在条件编译、代码组织等方面仍然非常实用。1.1 基本预处理指令类型C#支持以下几种主要的预处理指令#define和#undef用于定义和取消定义条件编译符号#if、#elif、#else、#endif用于条件编译#error和#warning生成编译时错误和警告#line控制编译器输出的行号和文件名#region和#endregion组织代码块#pragma提供编译器特定指令1.2 条件编译实战条件编译是预处理指令最常见的用途。假设我们有一个需要支持多平台的应用#define ANDROID //#define IOS using System; class PlatformService { public void ShowMessage() { #if ANDROID Console.WriteLine(Running on Android platform); #elif IOS Console.WriteLine(Running on iOS platform); #else Console.WriteLine(Running on unknown platform); #endif } }在实际项目中这些定义通常不是在代码中硬编码而是在项目属性或构建脚本中设置。重要提示条件编译符号是区分大小写的DEBUG和debug会被视为不同的符号。1.3 诊断指令的应用#error和#warning可以在特定条件下生成编译时消息#if NET40 #error .NET 4.0 is no longer supported #endif #warning This method will be deprecated in next version public void LegacyMethod() { // ... }这在以下场景特别有用标记即将废弃的API提醒未完成的功能强制使用特定编译配置2. C#反射机制全面剖析反射是C#中强大的元编程能力允许程序在运行时检查、修改甚至生成代码。虽然反射会带来一定的性能开销但在很多场景下是不可替代的。2.1 Type获取的三种方式获取Type对象是反射操作的起点主要有三种方式// 1. 使用typeof运算符 Type type1 typeof(string); // 2. 使用GetType()实例方法 string s hello; Type type2 s.GetType(); // 3. 使用Type.GetType静态方法 Type type3 Type.GetType(System.String);每种方式适用不同场景typeof在编译时就知道类型时使用GetType()在只有对象实例时使用Type.GetType()在只有类型名称字符串时使用2.2 反射核心操作示例通过反射可以动态调用方法、访问属性等using System; using System.Reflection; class Program { static void Main() { Type mathType typeof(Math); // 获取方法信息 MethodInfo sqrtMethod mathType.GetMethod(Sqrt, new[] { typeof(double) }); // 调用静态方法 double result (double)sqrtMethod.Invoke(null, new object[] { 16.0 }); Console.WriteLine($Square root of 16 is {result}); // 创建实例并设置属性 Type personType typeof(Person); object person Activator.CreateInstance(personType); PropertyInfo nameProp personType.GetProperty(Name); nameProp.SetValue(person, John Doe); Console.WriteLine($Person name: {nameProp.GetValue(person)}); } } class Person { public string Name { get; set; } }2.3 反射性能优化技巧反射虽然强大但性能较差以下是一些优化建议缓存反射结果将MethodInfo、PropertyInfo等存储在静态变量中使用Delegate.CreateDelegate将方法转换为委托使用dynamic关键字在已知接口的情况下使用表达式树构建并编译动态代码优化后的反射调用示例// 普通反射调用 MethodInfo method typeof(MyClass).GetMethod(MyMethod); method.Invoke(instance, new object[] { param }); // 优化后的调用 - 创建并缓存委托 private static ActionMyClass, int cachedDelegate; public static void FastReflectionCall(MyClass instance, int param) { if (cachedDelegate null) { MethodInfo method typeof(MyClass).GetMethod(MyMethod); cachedDelegate (ActionMyClass, int)Delegate.CreateDelegate( typeof(ActionMyClass, int), method); } cachedDelegate(instance, param); }3. 关键类深度解析3.1 Type类核心功能Type类是反射系统的核心提供以下关键功能类型信息查询IsClass、IsInterface、IsValueType等判断类型种类GetInterfaces()获取实现的接口BaseType获取基类成员访问GetMethods()、GetProperties()、GetFields()等GetMember()获取特定成员GetCustomAttributes()获取自定义特性实例操作Activator.CreateInstance()创建实例InvokeMember()动态调用成员3.2 Assembly类的关键作用Assembly类代表程序集是反射的另一个核心类// 加载程序集 Assembly assembly Assembly.LoadFrom(MyLibrary.dll); // 获取所有公共类型 Type[] types assembly.GetExportedTypes(); // 获取特定类型 Type targetType assembly.GetType(MyNamespace.MyClass); // 获取程序集信息 AssemblyName name assembly.GetName(); Console.WriteLine($Assembly: {name.Name}, Version: {name.Version});3.3 MethodInfo和PropertyInfo详解这两个类分别封装了方法和属性的元数据MethodInfo关键功能ReturnType获取返回类型GetParameters()获取参数信息Invoke()调用方法IsStatic判断是否为静态方法PropertyInfo关键功能PropertyType获取属性类型GetValue()/SetValue()获取/设置属性值CanRead/CanWrite判断可读可写性4. 高级应用场景4.1 动态插件系统实现反射常用于实现插件架构public interface IPlugin { string Name { get; } void Execute(); } public class PluginLoader { public ListIPlugin LoadPlugins(string path) { var plugins new ListIPlugin(); foreach (string file in Directory.GetFiles(path, *.dll)) { try { Assembly assembly Assembly.LoadFrom(file); foreach (Type type in assembly.GetTypes()) { if (typeof(IPlugin).IsAssignableFrom(type) !type.IsAbstract) { IPlugin plugin (IPlugin)Activator.CreateInstance(type); plugins.Add(plugin); } } } catch (Exception ex) { Console.WriteLine($Failed to load {file}: {ex.Message}); } } return plugins; } }4.2 动态代理实现利用反射可以实现AOP风格的动态代理public class DynamicProxyT : DispatchProxy { private T _decorated; protected override object Invoke(MethodInfo targetMethod, object[] args) { try { Console.WriteLine($Before {targetMethod.Name}); var result targetMethod.Invoke(_decorated, args); Console.WriteLine($After {targetMethod.Name}); return result; } catch (Exception ex) when (ex is TargetInvocationException) { Console.WriteLine($Error in {targetMethod.Name}: {ex.InnerException?.Message}); throw ex.InnerException ?? ex; } } public static T Create(T decorated) { object proxy CreateT, DynamicProxyT(); ((DynamicProxyT)proxy)._decorated decorated; return (T)proxy; } }4.3 序列化/反序列化工具反射可以用于实现通用的序列化工具public class ObjectSerializer { public string Serialize(object obj) { var builder new StringBuilder(); Type type obj.GetType(); builder.AppendLine($Type: {type.FullName}); foreach (PropertyInfo prop in type.GetProperties()) { if (prop.CanRead) { object value prop.GetValue(obj); builder.AppendLine(${prop.Name}: {value}); } } return builder.ToString(); } public T DeserializeT(string data) where T : new() { var lines data.Split(new[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries); T result new T(); Type type typeof(T); foreach (string line in lines.Skip(1)) // Skip type line { var parts line.Split(new[] { : }, 2); if (parts.Length 2) { string propName parts[0].Trim(); string valueStr parts[1].Trim(); PropertyInfo prop type.GetProperty(propName); if (prop ! null prop.CanWrite) { object value Convert.ChangeType(valueStr, prop.PropertyType); prop.SetValue(result, value); } } } return result; } }5. 性能考量与最佳实践5.1 反射性能对比操作直接调用反射调用优化后反射方法调用1x~100x~2x属性访问1x~50x~1.5x类型检查1x~10xN/A5.2 反射最佳实践避免频繁反射在循环中避免使用反射适当缓存缓存MethodInfo、PropertyInfo等对象使用接口约束尽可能使用接口或基类约束考虑替代方案对于已知类型使用dynamic对于高性能场景使用表达式树或IL生成安全考虑反射会绕过访问修饰符限制需谨慎使用5.3 表达式树优化示例对于需要高性能的动态调用可以使用表达式树public static class PropertyAccessor { private static readonly Dictionarystring, Delegate cache new Dictionarystring, Delegate(); public static FuncT, object CreateGetAccessorT(string propertyName) { string key ${typeof(T).FullName}.{propertyName}; if (!cache.TryGetValue(key, out var accessor)) { ParameterExpression param Expression.Parameter(typeof(T), instance); MemberExpression property Expression.Property(param, propertyName); UnaryExpression convert Expression.Convert(property, typeof(object)); accessor Expression.LambdaFuncT, object(convert, param).Compile(); cache[key] accessor; } return (FuncT, object)accessor; } public static ActionT, object CreateSetAccessorT(string propertyName) { string key ${typeof(T).FullName}.{propertyName}.set; if (!cache.TryGetValue(key, out var accessor)) { ParameterExpression instanceParam Expression.Parameter(typeof(T), instance); ParameterExpression valueParam Expression.Parameter(typeof(object), value); MemberExpression property Expression.Property(instanceParam, propertyName); UnaryExpression convertedValue Expression.Convert(valueParam, property.Type); BinaryExpression assign Expression.Assign(property, convertedValue); accessor Expression.LambdaActionT, object(assign, instanceParam, valueParam).Compile(); cache[key] accessor; } return (ActionT, object)accessor; } }这种方式的性能接近直接调用同时保留了动态性。