C#代理模式与委托机制详解及应用实践
1. C#代理模式深度解析在C#开发中代理这个概念实际上包含两个重要层面一是设计模式中的代理模式(Proxy Pattern)二是语言特性中的委托(Delegate)。很多初学者容易混淆这两者但它们在实际开发中都有着不可替代的作用。1.1 代理模式的核心思想代理模式属于结构型设计模式它为其他对象提供一种代理以控制对这个对象的访问。这种模式在实际项目中应用广泛特别是在需要控制对原始对象的访问时非常有用。典型的代理模式包含三个关键角色Subject抽象主题定义真实主题和代理主题的共同接口RealSubject真实主题实现真正的业务逻辑Proxy代理持有对真实主题的引用控制对真实主题的访问// 抽象主题 public interface IImage { void Display(); } // 真实主题 public class RealImage : IImage { private string _fileName; public RealImage(string fileName) { _fileName fileName; LoadFromDisk(); } private void LoadFromDisk() { Console.WriteLine($Loading {_fileName}); } public void Display() { Console.WriteLine($Displaying {_fileName}); } } // 代理 public class ProxyImage : IImage { private RealImage _realImage; private string _fileName; public ProxyImage(string fileName) { _fileName fileName; } public void Display() { if(_realImage null) { _realImage new RealImage(_fileName); } _realImage.Display(); } }1.2 代理模式的五种常见类型在实际开发中代理模式有几种常见的变体虚拟代理(Virtual Proxy)延迟创建开销大的对象保护代理(Protection Proxy)控制对原始对象的访问权限远程代理(Remote Proxy)为位于不同地址空间的对象提供本地代表智能引用代理(Smart Reference Proxy)在访问对象时执行附加操作缓存代理(Cache Proxy)为开销大的运算结果提供临时存储2. C#委托(Delegate)机制详解2.1 委托的本质与声明委托是C#中的一种类型它可以安全地封装方法类似于C中的函数指针但更加类型安全。委托的核心价值在于它允许将方法作为参数传递。声明委托的基本语法public delegate returnType DelegateName(parameterList);实际示例// 声明一个委托类型 public delegate void LogHandler(string message); // 使用委托 public class Logger { public void WriteToConsole(string message) { Console.WriteLine($Console: {message}); } public void WriteToFile(string message) { File.AppendAllText(log.txt, ${DateTime.Now}: {message}\n); } } // 客户端代码 var logger new Logger(); LogHandler logDelegate logger.WriteToConsole; logDelegate logger.WriteToFile; logDelegate(Application started);2.2 内置委托类型C#提供了几种内置的通用委托类型可以避免重复定义相似的委托Action表示没有返回值的方法Actionstring print Console.WriteLine; print(Hello World);Func表示有返回值的方法Funcint, int, int add (x, y) x y; Console.WriteLine(add(3, 5)); // 输出8Predicate表示返回bool的方法Predicateint isEven x x % 2 0; Console.WriteLine(isEven(4)); // 输出True3. 代理模式与委托的实战应用3.1 实现一个延迟加载代理下面是一个完整的延迟加载代理实现展示了如何结合代理模式和委托public interface IDataService { Liststring GetData(); } public class ExpensiveDataService : IDataService { public Liststring GetData() { // 模拟耗时操作 Thread.Sleep(3000); return new Liststring { Data1, Data2, Data3 }; } } public class LazyDataServiceProxy : IDataService { private LazyListstring _data; private IDataService _realService; public LazyDataServiceProxy() { _realService new ExpensiveDataService(); _data new LazyListstring(() _realService.GetData()); } public Liststring GetData() { return _data.Value; } } // 使用示例 var proxy new LazyDataServiceProxy(); Console.WriteLine(Proxy created, real service not initialized yet); // 第一次访问会初始化真实服务 var data proxy.GetData(); Console.WriteLine($Data loaded: {string.Join(, , data)});3.2 委托在事件系统中的应用委托在C#事件系统中扮演着核心角色。下面是一个完整的事件系统实现示例// 定义事件参数 public class OrderEventArgs : EventArgs { public string OrderId { get; set; } public DateTime OrderTime { get; set; } } // 发布者 public class OrderProcessor { // 定义基于委托的事件 public event EventHandlerOrderEventArgs OrderProcessed; public void ProcessOrder(string orderId) { // 处理订单逻辑... Thread.Sleep(1000); // 触发事件 OnOrderProcessed(new OrderEventArgs { OrderId orderId, OrderTime DateTime.Now }); } protected virtual void OnOrderProcessed(OrderEventArgs e) { OrderProcessed?.Invoke(this, e); } } // 订阅者 public class NotificationService { public void SendConfirmation(object sender, OrderEventArgs e) { Console.WriteLine($Sending confirmation for order {e.OrderId}); } } // 使用示例 var processor new OrderProcessor(); var notifier new NotificationService(); // 订阅事件 processor.OrderProcessed notifier.SendConfirmation; // 处理订单会触发通知 processor.ProcessOrder(ORD12345);4. 高级应用与性能优化4.1 动态代理实现AOP使用Castle DynamicProxy可以实现面向切面编程(AOP)// 需要安装Castle.Core NuGet包 public class LoggingInterceptor : IInterceptor { public void Intercept(IInvocation invocation) { Console.WriteLine($Before {invocation.Method.Name}); var watch Stopwatch.StartNew(); invocation.Proceed(); // 调用实际方法 watch.Stop(); Console.WriteLine($After {invocation.Method.Name}, took {watch.ElapsedMilliseconds}ms); } } public interface ICalculator { int Add(int x, int y); } public class Calculator : ICalculator { public int Add(int x, int y) x y; } // 创建动态代理 var generator new ProxyGenerator(); var calculator generator.CreateInterfaceProxyWithTargetICalculator( new Calculator(), new LoggingInterceptor()); var result calculator.Add(3, 5); Console.WriteLine($Result: {result});4.2 委托性能优化技巧避免频繁创建委托委托是引用类型频繁创建会导致GC压力// 不好每次调用都创建新委托 for(int i 0; i 1000; i) { Action action () Console.WriteLine(i); action(); } // 好重用委托实例 Actionint action Console.WriteLine; for(int i 0; i 1000; i) { action(i); }使用静态方法静态方法委托比实例方法委托性能更好public static class Formatter { public static string FormatDate(DateTime date) date.ToString(yyyy-MM-dd); } // 静态方法委托 FuncDateTime, string formatter Formatter.FormatDate;多播委托的调用顺序多播委托按添加顺序调用使用GetInvocationList可以控制调用Action multi () Console.WriteLine(First); multi () Console.WriteLine(Second); // 手动控制调用顺序 foreach(Action handler in multi.GetInvocationList().Reverse()) { handler(); }5. 常见问题与解决方案5.1 代理模式常见问题问题1代理导致性能下降症状使用代理后系统响应变慢解决方案对于频繁访问的对象考虑使用轻量级代理实现缓存机制减少重复计算评估是否真的需要代理模式问题2代理与真实对象不一致症状代理行为与真实对象表现不同解决方案确保代理正确转发所有方法调用使用接口约束代理和真实对象的行为实现全面的单元测试5.2 委托使用中的陷阱陷阱1委托引用导致内存泄漏public class Publisher { public event EventHandler SomethingHappened; } public class Subscriber { public Subscriber(Publisher pub) { pub.SomethingHappened HandleEvent; } private void HandleEvent(object sender, EventArgs e) { Console.WriteLine(Event handled); } } // 使用示例 var pub new Publisher(); var sub new Subscriber(pub); // 即使sub不再被引用pub仍然持有对sub的引用 // 解决方案实现IDisposable或在适当时候取消订阅陷阱2多线程环境下的委托调用public class EventExample { public event EventHandler Updated; public void Update() { // 不安全的调用方式 // Updated?.Invoke(this, EventArgs.Empty); // 线程安全的调用方式 var handlers Updated; if(handlers ! null) { foreach(EventHandler handler in handlers.GetInvocationList()) { try { handler(this, EventArgs.Empty); } catch(Exception ex) { // 处理单个handler的异常 Console.WriteLine($Handler failed: {ex.Message}); } } } } }陷阱3lambda表达式捕获变量for(int i 0; i 5; i) { Task.Run(() Console.WriteLine(i)); } // 可能输出5个5而不是0-4 // 解决方案使用临时变量 for(int i 0; i 5; i) { int temp i; Task.Run(() Console.WriteLine(temp)); }6. 实际项目中的应用建议6.1 何时使用代理模式延迟初始化当对象创建开销大时访问控制需要权限验证的场景本地代表与远程服务交互时日志记录需要记录方法调用时缓存需要缓存昂贵操作结果时6.2 委托的最佳实践使用内置委托类型优先使用Action/Func/Predicate事件模式标准化遵循sender/args模式明确委托用途避免过度使用导致代码难以理解注意生命周期及时取消订阅避免内存泄漏考虑性能高频调用的场景避免委托开销6.3 混合使用代理和委托的案例下面是一个结合代理模式和委托的缓存实现public interface IDataFetcher { string FetchData(string key); } public class RemoteDataFetcher : IDataFetcher { public string FetchData(string key) { // 模拟远程调用 Thread.Sleep(1000); return $Data for {key}; } } public class CachingProxy : IDataFetcher { private readonly IDataFetcher _realFetcher; private readonly Dictionarystring, string _cache new(); public event Actionstring CacheMiss; public CachingProxy(IDataFetcher realFetcher) { _realFetcher realFetcher; } public string FetchData(string key) { if(_cache.TryGetValue(key, out var data)) { return data; } CacheMiss?.Invoke(key); data _realFetcher.FetchData(key); _cache[key] data; return data; } } // 使用示例 var fetcher new CachingProxy(new RemoteDataFetcher()); fetcher.CacheMiss key Console.WriteLine($Cache miss for {key}); // 第一次调用会触发CacheMiss事件 Console.WriteLine(fetcher.FetchData(user1)); // 第二次调用从缓存获取 Console.WriteLine(fetcher.FetchData(user1));在实际项目中理解并正确运用C#中的代理模式和委托机制可以显著提高代码的灵活性、可维护性和性能。关键是要根据具体场景选择合适的技术方案并遵循最佳实践来避免常见的陷阱。

相关新闻

ESP32 I2S音频开发与优化实战

ESP32 I2S音频开发与优化实战

1. ESP32 I2S音频开发核心解析在嵌入式音频开发领域,ESP32凭借其双核处理能力和丰富的外设接口,成为了低成本音频项目的首选方案。我最近完成了一个基于INMP441麦克风和PCM5102解码器的语音采集系统,实测采样率可达16kHz/16bit,完…

2026/7/19 21:30:42 阅读更多 →
042-Form Kit服务卡片

042-Form Kit服务卡片

042 — Form Kit 服务卡片:从 2x2 到 4x4 的桌面数据展示实践 简介 服务卡片是鸿蒙系统的标志性能力之一,它让用户无需打开应用就能在桌面上快速查看关键信息。MoneyTrack 利用 Form Kit 实现了两种尺寸的桌面卡片:2x2 的迷你卡片&#xff…

2026/7/19 21:30:42 阅读更多 →
Android构建变体:Gradle多版本管理实战指南

Android构建变体:Gradle多版本管理实战指南

1. 构建变体的本质与价值在Android应用开发中,构建变体(Build Variant)是Gradle构建系统的核心概念之一。简单来说,构建变体就是通过不同维度的组合,生成具有差异化特性的应用版本。这就像一家汽车工厂,用相…

2026/7/19 21:29:41 阅读更多 →

最新新闻

万能驱动 26v3:Win10/Win11 驱动更新解析

万能驱动 26v3:Win10/Win11 驱动更新解析

🔥 个人主页: 杨利杰YJlio ❄️ 个人专栏: 《Windows 疑难杂症与工单复盘案例库》 《Sysinternals实战教程》 《WINDOWS教程》 《Windows PowerShell 实战》 《IOS插件分析测试》 《超简单:用Python让Excel飞起来》…

2026/7/20 10:14:13 阅读更多 →
Unity游戏实时翻译插件XUnity.AutoTranslator配置与优化指南

Unity游戏实时翻译插件XUnity.AutoTranslator配置与优化指南

1. 项目概述:为什么我们需要一个专业的游戏翻译方案如果你是一个喜欢玩各种独立游戏或者小众作品的玩家,肯定遇到过这样的场景:打开一款口碑极佳的Unity游戏,结果发现它只有英文、日文或者韩文界面。查字典、截图翻译、切屏看攻略…

2026/7/20 10:14:13 阅读更多 →
TMS320F28003x PIE中断模块详解:从寄存器配置到实战调试

TMS320F28003x PIE中断模块详解:从寄存器配置到实战调试

1. 项目概述与PIE模块核心价值 在嵌入式实时控制领域,尤其是像TI C2000系列这样的高性能微控制器上,中断响应速度和处理效率直接决定了系统的实时性能。当你面对一个集成了数十个甚至上百个外设的MCU时,一个核心矛盾就出现了:CPU自…

2026/7/20 10:14:13 阅读更多 →
【项目源码38756】基于 Spring Boot 的流浪动物救助与管理系统:领养、救助、志愿者任务一站式管理

【项目源码38756】基于 Spring Boot 的流浪动物救助与管理系统:领养、救助、志愿者任务一站式管理

把“发现流浪动物—发布信息—申请领养—救助记录—志愿者培训”做成完整闭环文章标签:Spring Boot、Java、MySQL、流浪动物救助、动物领养、后台管理系统、毕业设计这篇文章适合谁?✓ 想做公益类、宠物领养类 Java Web 项目的同学✓ 需要 Spring Boot 毕…

2026/7/20 10:14:13 阅读更多 →
波司登转型成功:从保暖工具到时尚单品的品牌升级

波司登转型成功:从保暖工具到时尚单品的品牌升级

1. 波司登的转型拐点解析羽绒服行业龙头波司登(3998.HK)在经历战略调整后,近年业绩呈现明显拐点特征。从2018年启动"聚焦主航道、收缩多元化"战略以来,公司营收从2018财年的88.8亿元增长至2023财年的162.1亿元&#xff…

2026/7/20 10:14:12 阅读更多 →
3分钟搞定安卓投屏:免费高效的scrcpy终极使用指南

3分钟搞定安卓投屏:免费高效的scrcpy终极使用指南

3分钟搞定安卓投屏:免费高效的scrcpy终极使用指南 【免费下载链接】scrcpy Display and control your Android device 项目地址: https://gitcode.com/GitHub_Trending/sc/scrcpy 想要在电脑上流畅控制安卓手机吗?scrcpy这款开源神器让你无需Root…

2026/7/20 10:13:12 阅读更多 →

日新闻

2026 WAIC:努比亚二代“豆包手机”NaviX Ultra亮相,智能体验全面升级!

2026 WAIC:努比亚二代“豆包手机”NaviX Ultra亮相,智能体验全面升级!

7月18日智东西消息,在2026 WAIC期间,努比亚联合字节豆包打造的二代“豆包手机”努比亚NaviX Ultra首次亮相,相比一代有诸多升级。智能体手机理念中兴通讯终端事业部总裁、努比亚总裁倪飞表示,智能体手机要从人操作手机变为手机帮人…

2026/7/20 0:00:34 阅读更多 →
努比亚NaviX Ultra亮相WAIC,智能体手机能否让用户生活更简单?

努比亚NaviX Ultra亮相WAIC,智能体手机能否让用户生活更简单?

努比亚NaviX Ultra:外观与功能双升级在2026 WAIC期间,首次亮相的努比亚NaviX Ultra吸引了众多目光。它是努比亚联合字节豆包打造的二代“豆包手机”,与一代努比亚M153相比,外观设计变化较大。其机身背部搭载横向排布的大尺寸影像模…

2026/7/20 0:00:34 阅读更多 →
C# 将逗号分割的字符串转换为long,并添加到List<long>

C# 将逗号分割的字符串转换为long,并添加到List<long>

目录 方法1:使用Split和Convert.ToInt64 方法2:使用LINQ的Select和ToList 方法3:使用TryParse进行异常安全转换(推荐) 如果您喜欢此文章,请收藏、点赞、评论,谢谢,祝您快乐每一天…

2026/7/20 0:00:34 阅读更多 →

周新闻

Go语言静态资源打包方案对比与实践指南

Go语言静态资源打包方案对比与实践指南

1. 项目背景与核心需求在Go语言开发中,我们经常需要处理静态资源文件的打包问题。无论是Web应用的模板文件、前端资源,还是配置文件、证书等,都需要随程序一起分发。传统做法是将这些文件与编译后的二进制文件放在同一目录下,但这…

2026/7/20 5:57:49 阅读更多 →
Go语言实现高性能LDAP认证服务的架构与实践

Go语言实现高性能LDAP认证服务的架构与实践

1. 项目背景与核心价值LDAP(轻量级目录访问协议)作为企业级身份认证的黄金标准,已经服务了超过80%的财富500强公司。我在金融科技领域实施统一认证体系时,发现传统Java方案存在启动慢、内存占用高等痛点。而Go语言凭借其协程并发模…

2026/7/20 4:31:26 阅读更多 →
【AI面试官实战指南】:用ChatGPT模拟10类高频技术岗面试,3天提升应答精准度92%

【AI面试官实战指南】:用ChatGPT模拟10类高频技术岗面试,3天提升应答精准度92%

更多请点击: https://intelliparadigm.com 第一章:AI面试官实战指南的核心价值与适用场景 AI面试官并非替代人类HR的“黑箱工具”,而是以可解释、可审计、可迭代的方式,赋能招聘全链路的关键基础设施。其核心价值在于将主观经验沉…

2026/7/20 5:56:42 阅读更多 →

月新闻