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; } }在实际项目中我经常发现开发者过度使用代理模式会导致系统复杂性增加。一个实用的建议是只有当确实需要控制访问或添加横切关注点时才使用代理对于简单的功能扩展继承或组合可能是更简单的选择。

相关新闻

Android开发:XUtils3环境搭建与核心功能详解

Android开发:XUtils3环境搭建与核心功能详解

1. XUtils3 环境搭建全流程解析 XUtils3 是 Android 开发中常用的工具库,它封装了网络请求、数据库操作、图片加载等常用功能。最近在帮团队搭建新项目时,发现很多新人对于如何正确集成 XUtils3 还存在困惑。这里分享下我在多个项目中总结的环境搭建方法…

2026/10/19 7:12:16 阅读更多 →
Windows 11系统清理优化终极指南:3步快速提升性能与隐私保护

Windows 11系统清理优化终极指南:3步快速提升性能与隐私保护

Windows 11系统清理优化终极指南:3步快速提升性能与隐私保护 【免费下载链接】Win11Debloat A simple, lightweight PowerShell script that allows you to remove pre-installed apps, disable telemetry, as well as perform various other changes to declutter …

2026/10/17 23:48:32 阅读更多 →
AI产品不是软件:概率性治理与可存活失败设计

AI产品不是软件:概率性治理与可存活失败设计

1. 项目概述:这不是软件,是全新物种的诞生现场你有没有过这种感觉:花三个月打磨出一个AI功能,上线后用户反馈“偶尔答得离谱”,技术团队立刻拉群排查——结果发现模型代码没改、API调用正常、日志里连个报错都没有。最…

2026/10/18 3:20:27 阅读更多 →

最新新闻

C语言实现链表、栈与队列:从指针操作到内存管理实战

C语言实现链表、栈与队列:从指针操作到内存管理实战

链表的指针操作、栈的先进后出、队列的先进先出,这三个基础数据结构在 C 语言里的实现,几乎是每一位想搞懂底层原理的开发者都绕不开的关卡。我当年第一次写链表时,头指针、尾指针、临时指针搅在一起,一调试就是大半个晚上&#x…

2026/10/19 7:12:10 阅读更多 →
用C语言手写链表、栈、队列:核心实现与避坑指南

用C语言手写链表、栈、队列:核心实现与避坑指南

写数据结构代码这件事,很多朋友可能都觉得“不就是上课学过、考试背过的东西嘛”,但真到了面试手写、或者项目里需要自己封装一个队列缓冲串口数据的时候,才发现里面全是细节。我用C语言把链表、栈、队列这三种最基础的线性结构从头到尾实现过…

2026/10/19 7:12:10 阅读更多 →
用ChatGPT提升开发效率:从提示词到代码落地的完整工作流

用ChatGPT提升开发效率:从提示词到代码落地的完整工作流

有一次,我被一个临时需求绊了一下午:某个内部数据平台要出一份按用户聚合的订单报表,字段对不上、文件编码还不统一。折腾到一半,我抱着试试看的心态把需求整理成一段话发给了ChatGPT,它给的Python脚本帮我省掉了大半天…

2026/10/19 7:12:10 阅读更多 →
基于SE-ResNet的C-MAPSS涡扇发动机剩余寿命预测Matlab实践

基于SE-ResNet的C-MAPSS涡扇发动机剩余寿命预测Matlab实践

C-MAPSS数据集做剩余寿命预测,基本是设备健康管理领域绕不开的入门关。涡扇发动机的退化仿真数据、四套不同工况组合的子集、公开的评估口径,让这个数据集成了算法对比的标准场地。这段时间我用Matlab把基于SE-ResNet的发动机寿命预测模型完整做了一遍&a…

2026/10/19 7:12:10 阅读更多 →
C语言作业总WA?从判题机原理到测试用例,避开在线判题那些坑

C语言作业总WA?从判题机原理到测试用例,避开在线判题那些坑

简介:这份资料针对北理工乐学平台的C语言程序设计课程测试,汇集了全部测试题目的参考答案与可执行程序,涵盖日期计算、链表操作、指针应用、字符处理、图形输出等常见考点,内容覆盖基础语法与难点专题,适合正在学习C语…

2026/10/19 7:12:10 阅读更多 →
企业合规智能化:LLM+RPA+Agent架构设计与实战

企业合规智能化:LLM+RPA+Agent架构设计与实战

企业合规这事儿,我这两年被问得最多的就是一句话:“明明配了人、定了制度、走了流程,怎么还总是出事?”其实答案很扎心:纯靠人工盯合规,本质上是在用有限的人力对抗无限变化的规则和系统。就拿供应商准入审…

2026/10/19 7:11:10 阅读更多 →

日新闻

频率跟踪型PWM电源设计:臭氧发生器谐振点漂移与软开关实现

频率跟踪型PWM电源设计:臭氧发生器谐振点漂移与软开关实现

简介:本资源为电源技术方向的学术研究文档,聚焦介质阻挡放电型臭氧发生器电源的频率跟踪型PWM控制策略,面向电力电子、高压电源及臭氧应用领域的科研人员与工程技术人员。针对负载呈容性、等效电容随外加电压升高而增大、谐振频率随之漂移的难…

2026/10/19 0:00:47 阅读更多 →
Vibe Coding 遇上 TaoToken:把开发者思维圣殿的灵感流接入统一 Key 通道

Vibe Coding 遇上 TaoToken:把开发者思维圣殿的灵感流接入统一 Key 通道

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/19 0:00:47 阅读更多 →
HundredCV-Chat话题建模实战教程:利用4,871个内置话题标签构建主题分析系统

HundredCV-Chat话题建模实战教程:利用4,871个内置话题标签构建主题分析系统

【免费下载链接】HundredCV-Chat 项目地址: https://ai.gitcode.com/hf_mirrors/Jax-dan/HundredCV-Chat 点击查看 免费下载 HundredCV-Chat 是一个由 100 位青年简历数据开发而来的中文多轮对话数据集,共包含 24,750 组日常闲聊对话和 4,871 个话题标签…

2026/10/19 0:00:47 阅读更多 →

周新闻

基于GMM的语音识别系统原理与MATLAB实现详解

基于GMM的语音识别系统原理与MATLAB实现详解

说到基于高斯混合模型(GMM)的语音识别系统,很多人第一反应就是一堆数学公式,觉得门槛很高。但如果你真的在MATLAB里把它落地跑通,会发现核心其实就是三件事:把声音变成特征向量,用GMM给每个类别…

2026/10/18 0:00:55 阅读更多 →
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理这四个字听起来挺唬人,但落到具体操作上,无非就是让计算机按你的想法“摆弄”像素。我在一个模拟项目X里用了一套特别经典的基础处理流程:对图像做反白、改调色板、彩色转灰度,最后把像素数据导出成txt文件。单看每一…

2026/10/18 0:00:55 阅读更多 →
机器人大脑技术盘点:具身智能的感知、决策与数据闭环

机器人大脑技术盘点:具身智能的感知、决策与数据闭环

如果你的信息流最近也天天刷到“机器人大脑”这个词,你会发现一个很有意思的现象:每个人说的“大脑”根本不是同一个东西。有人指的是大语言模型,有人指的是运动控制系统,还有人指的是能理解物理世界的端到端模型。在2026年这个时…

2026/10/19 1:30:52 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/19 2:54:50 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/17 17:22:31 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/18 12:16:16 阅读更多 →