C#代理模式详解与应用实践

发布时间:2026/7/19 19:44:36

C#代理模式详解与应用实践 1. C#代理模式深度解析在C#开发中代理模式Proxy Pattern是一种结构型设计模式它为其他对象提供一种代理以控制对这个对象的访问。这种模式在需要控制对象访问权限、延迟加载或添加额外功能时特别有用。1.1 代理模式的核心概念代理模式主要包含三个角色Subject抽象主题定义真实主题和代理主题的共同接口RealSubject真实主题实现真正的业务逻辑Proxy代理持有真实主题的引用控制对真实主题的访问// 抽象主题接口 public interface ISubject { void Request(); } // 真实主题 public class RealSubject : ISubject { public void Request() { Console.WriteLine(RealSubject: Handling Request.); } } // 代理类 public class Proxy : ISubject { private RealSubject _realSubject; public void Request() { if (_realSubject null) { _realSubject new RealSubject(); } // 可以在调用真实对象前后添加额外逻辑 Console.WriteLine(Proxy: Pre-processing); _realSubject.Request(); Console.WriteLine(Proxy: Post-processing); } }1.2 代理模式的典型应用场景虚拟代理延迟创建开销大的对象保护代理控制对原始对象的访问权限远程代理为位于不同地址空间的对象提供本地代表智能引用在访问对象时执行额外操作如引用计数提示在.NET框架中WCF服务就是使用代理模式的典型例子客户端通过服务代理与远程服务通信。2. C#动态代理实现2.1 使用RealProxy实现动态代理.NET框架提供了RealProxy类来实现动态代理using System.Runtime.Remoting.Proxies; using System.Runtime.Remoting.Messaging; public class LoggingProxy : RealProxy { private readonly object _target; public LoggingProxy(object target) : base(target.GetType()) { _target target; } public override IMessage Invoke(IMessage msg) { var methodCall msg as IMethodCallMessage; Console.WriteLine($Before invoking {methodCall.MethodName}); try { var result methodCall.MethodBase.Invoke(_target, methodCall.Args); Console.WriteLine($After invoking {methodCall.MethodName}); return new ReturnMessage(result, null, 0, methodCall.LogicalCallContext, methodCall); } catch (Exception ex) { Console.WriteLine($Error in {methodCall.MethodName}: {ex.Message}); return new ReturnMessage(ex, methodCall); } } } // 使用示例 public interface IService { void DoWork(); } public class Service : IService { public void DoWork() { Console.WriteLine(Doing actual work...); } } var service new Service(); var proxy new LoggingProxy(service); var serviceProxy (IService)proxy.GetTransparentProxy(); serviceProxy.DoWork();2.2 使用Castle DynamicProxyCastle DynamicProxy是一个流行的动态代理库using Castle.DynamicProxy; public class LoggingInterceptor : IInterceptor { public void Intercept(IInvocation invocation) { Console.WriteLine($Before {invocation.Method.Name}); invocation.Proceed(); Console.WriteLine($After {invocation.Method.Name}); } } // 使用示例 var generator new ProxyGenerator(); var service new Service(); var proxy generator.CreateInterfaceProxyWithTargetIService( service, new LoggingInterceptor()); proxy.DoWork();3. 代理模式的高级应用3.1 AOP编程实现面向切面编程AOP常使用代理模式实现public class CacheAspect : IInterceptor { private readonly MemoryCache _cache MemoryCache.Default; public void Intercept(IInvocation invocation) { var cacheKey ${invocation.TargetType.FullName}.{invocation.Method.Name}; if (_cache.Contains(cacheKey)) { invocation.ReturnValue _cache.Get(cacheKey); return; } invocation.Proceed(); _cache.Add(cacheKey, invocation.ReturnValue, DateTimeOffset.Now.AddMinutes(5)); } } // 使用示例 var generator new ProxyGenerator(); var service new Service(); var cachedService generator.CreateInterfaceProxyWithTargetIService( service, new CacheAspect());3.2 性能监控代理public class PerformanceMonitorProxy : IInterceptor { public void Intercept(IInvocation invocation) { var stopwatch Stopwatch.StartNew(); invocation.Proceed(); stopwatch.Stop(); Console.WriteLine(${invocation.Method.Name} executed in {stopwatch.ElapsedMilliseconds}ms); } }4. 代理模式的注意事项与最佳实践4.1 常见问题与解决方案接口代理与类代理的区别接口代理只能拦截接口方法类代理可以拦截虚方法virtual性能考虑动态代理会引入一定的性能开销对于性能敏感场景考虑使用编译时代理如Source Generators循环引用问题代理对象持有真实对象引用可能导致内存泄漏实现IDisposable接口确保资源释放4.2 最佳实践保持代理轻量级代理类不应包含复杂业务逻辑明确代理目的每个代理类应专注于单一功能如日志、缓存合理使用组合可以通过组合多个代理实现复杂功能考虑线程安全确保代理在多线程环境下正常工作// 线程安全的代理示例 public class ThreadSafeProxy : ISubject { private readonly ISubject _realSubject; private readonly object _lock new object(); public ThreadSafeProxy(ISubject realSubject) { _realSubject realSubject; } public void Request() { lock (_lock) { _realSubject.Request(); } } }5. 代理模式与其他模式的比较5.1 代理模式与装饰器模式特性代理模式装饰器模式目的控制访问添加功能对象创建通常由代理控制通常由客户端控制关注点访问控制、延迟加载等动态添加职责5.2 代理模式与适配器模式特性代理模式适配器模式目的控制访问转换接口接口关系相同接口不同接口使用场景访问控制、缓存等集成不兼容接口6. 实际项目中的应用案例6.1 ORM框架中的延迟加载public class ProductProxy : Product { private bool _isLoaded; private readonly FuncProduct _loader; public ProductProxy(FuncProduct loader) { _loader loader; } public override string Name { get { if (!_isLoaded) { var realProduct _loader(); // 复制属性值 _isLoaded true; } return base.Name; } set base.Name value; } }6.2 Web API客户端代理public class ApiClientProxy : IApiClient { private readonly HttpClient _httpClient; private readonly ILogger _logger; public ApiClientProxy(HttpClient httpClient, ILogger logger) { _httpClient httpClient; _logger logger; } public async TaskResponse GetDataAsync(Request request) { _logger.LogInformation(Sending request to API); try { var response await _httpClient.PostAsJsonAsync(api/endpoint, request); response.EnsureSuccessStatusCode(); return await response.Content.ReadAsAsyncResponse(); } catch (Exception ex) { _logger.LogError(ex, API request failed); throw; } } }7. 性能优化与高级技巧7.1 代理缓存策略public class ProxyCacheT where T : class { private static readonly ConcurrentDictionaryType, T _cache new(); private readonly FuncT _factory; public ProxyCache(FuncT factory) { _factory factory; } public T GetProxy() { return _cache.GetOrAdd(typeof(T), _ { var generator new ProxyGenerator(); return generator.CreateInterfaceProxyWithoutTargetT(new LoggingInterceptor()); }); } }7.2 轻量级代理实现对于性能敏感场景可以手动实现轻量级代理public class LightweightProxyT : DispatchProxy where T : class { private T _decorated; private ActionT _preAction; private ActionT _postAction; protected override object Invoke(MethodInfo targetMethod, object[] args) { _preAction?.Invoke(_decorated); var result targetMethod.Invoke(_decorated, args); _postAction?.Invoke(_decorated); return result; } public static T Create(T decorated, ActionT preAction null, ActionT postAction null) { object proxy CreateT, LightweightProxyT(); ((LightweightProxyT)proxy).SetParameters(decorated, preAction, postAction); return (T)proxy; } private void SetParameters(T decorated, ActionT preAction, ActionT postAction) { _decorated decorated ?? throw new ArgumentNullException(nameof(decorated)); _preAction preAction; _postAction postAction; } }8. 测试与调试代理类8.1 单元测试策略[TestClass] public class ProxyTests { [TestMethod] public void LoggingProxy_ShouldLogMethodCalls() { // Arrange var logger new StringWriter(); Console.SetOut(logger); var service new Service(); var proxy new LoggingProxy(service); var serviceProxy (IService)proxy.GetTransparentProxy(); // Act serviceProxy.DoWork(); // Assert var log logger.ToString(); Assert.IsTrue(log.Contains(Before invoking DoWork)); Assert.IsTrue(log.Contains(After invoking DoWork)); } }8.2 调试技巧检查代理类型使用GetType()查看代理对象的实际类型断点设置在拦截器或代理方法中设置断点日志记录详细记录代理的调用过程和参数性能分析使用性能分析工具测量代理引入的开销9. 现代C#中的代理模式演进9.1 Source Generators实现编译时代理C# 9.0引入的Source Generators可以在编译时生成代理代码[Generator] public class ProxyGenerator : ISourceGenerator { public void Execute(GeneratorExecutionContext context) { // 分析上下文中的接口类型 // 生成代理类源代码 // 添加到编译上下文 } public void Initialize(GeneratorInitializationContext context) { // 初始化逻辑 } }9.2 使用DefaultInterfaceMethod实现代理C# 8.0的默认接口方法可以用于简单代理场景public interface IService { void DoWork() { Console.WriteLine(Default implementation); } } public class ServiceProxy : IService { private readonly IService _realService; public ServiceProxy(IService realService) { _realService realService; } void IService.DoWork() { Console.WriteLine(Proxy pre-processing); _realService.DoWork(); Console.WriteLine(Proxy post-processing); } }10. 安全考虑与边界情况10.1 安全代理实现public class SecurityProxy : ISubject { private readonly ISubject _realSubject; private readonly IPrincipal _principal; public SecurityProxy(ISubject realSubject, IPrincipal principal) { _realSubject realSubject; _principal principal; } public void Request() { if (!_principal.IsInRole(Admin)) { throw new SecurityException(Access denied); } _realSubject.Request(); } }10.2 处理特殊边界情况异步方法代理确保正确处理async/awaitref/out参数在拦截器中正确处理参数传递泛型方法确保类型参数正确传递事件处理代理类应正确转发事件public class AsyncProxy : IAsyncService { private readonly IAsyncService _realService; public AsyncProxy(IAsyncService realService) { _realService realService; } public async Taskstring GetDataAsync() { Console.WriteLine(Before async call); var result await _realService.GetDataAsync(); Console.WriteLine(After async call); return result; } }在实际项目中我经常发现开发者过度使用代理模式会导致系统复杂性增加。一个实用的建议是只有当确实需要控制访问或添加横切关注点时才使用代理对于简单的功能扩展继承或组合可能是更简单的选择。

相关新闻