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:39阅读更多 →
NVIDIA推Metropolis视觉AI 做图像识别终于不用堆人头了

NVIDIA推Metropolis视觉AI 做图像识别终于不用堆人头了

说实话 做计算机视觉应用一直是个挺分裂的事情。一方面 模型能力在快速提升——去年CLIP、今年各种视觉语言模型 准确率越来越高。另一方面 真的把一个视觉AI应用推到生产环境 涉及的工作量大得离谱。你得收集数据、标注数据、训练模型、部署、监控、回传数据、再训练。光数据标…

2026/7/19 21:28:39阅读更多 →
Godot 4.0脚本语言选择:GDScript与C#深度对比与实战指南

Godot 4.0脚本语言选择:GDScript与C#深度对比与实战指南

1. 项目概述:为什么要在乎脚本语言的选择?如果你刚开始接触Godot 4.0,或者从其他引擎(比如Unity)转过来,面对项目创建时那个“脚本语言”的下拉框,可能会有点犹豫。GDScript是默认的&#xff0c…

2026/7/19 21:28:39阅读更多 →
HoRain云--Codex 斜杆 / 命令

HoRain云--Codex 斜杆 / 命令

🎬 HoRain云小助手:个人主页 🔥 个人专栏: 《Linux 系列教程》《c语言教程》 ⛺️生活的理想,就是为了理想的生活! ⛳️ 推荐 前些天发现了一个超棒的服务器购买网站,性价比超高,大内存超划算!…

2026/7/20 11:25:32阅读更多 →
音乐格式转换终极指南:免费解锁各大平台加密音频的完整方案

音乐格式转换终极指南:免费解锁各大平台加密音频的完整方案

音乐格式转换终极指南:免费解锁各大平台加密音频的完整方案 【免费下载链接】unlock-music 在浏览器中解锁加密的音乐文件。原仓库: 1. https://github.com/unlock-music/unlock-music ;2. https://git.unlock-music.dev/um/web 项目地址: …

2026/7/20 11:25:32阅读更多 →
终极实战指南:如何实现无人机群厘米级定位?基于UWB与IMU融合技术的完整解决方案

终极实战指南:如何实现无人机群厘米级定位?基于UWB与IMU融合技术的完整解决方案

终极实战指南:如何实现无人机群厘米级定位?基于UWB与IMU融合技术的完整解决方案 【免费下载链接】uwb-localization Accurate 3D Localization for MAV Swarms by UWB and IMU Fusion. ICCA 2018 项目地址: https://gitcode.com/gh_mirrors/uw/uwb-loc…

2026/7/20 11:25:32阅读更多 →
80%时间浪费在流程上?3个关键点破解供应链合同“效率黑洞“

80%时间浪费在流程上?3个关键点破解供应链合同“效率黑洞“

采购合同是企业管理中最容易被忽略的"效率黑洞"。摘要:供应链合同管理消耗企业80%无效流程时间。本文揭示采购合同数字化的三大关键——供应商零门槛、模板标准化、签署即存证,帮助企业将签约周期从7-10天缩短至1-2天,实现从"…

2026/7/20 11:25:32阅读更多 →
3大突破:如何用雷达技术重构智能感知边界?

3大突破:如何用雷达技术重构智能感知边界?

3大突破:如何用雷达技术重构智能感知边界? 【免费下载链接】esp-iot-solution Espressif IoT Library. IoT Device Drivers, Documentations and Solutions. 项目地址: https://gitcode.com/GitHub_Trending/es/esp-iot-solution 想象一下&#x…

2026/7/20 11:25:32阅读更多 →
5分钟掌握163MusicLyrics:免费歌词下载神器,一站式解决音乐歌词获取难题

5分钟掌握163MusicLyrics:免费歌词下载神器,一站式解决音乐歌词获取难题

5分钟掌握163MusicLyrics:免费歌词下载神器,一站式解决音乐歌词获取难题 【免费下载链接】163MusicLyrics 云音乐歌词获取处理工具【网易云、QQ音乐】 项目地址: https://gitcode.com/GitHub_Trending/16/163MusicLyrics 还在为找不到音乐歌词而烦…

2026/7/20 11:23:31阅读更多 →
Go语言静态资源打包方案对比与实践指南

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

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

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

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

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

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

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

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

2026/7/20 0:50:54阅读更多 →
2026 WAIC:努比亚二代“豆包手机”NaviX Ultra亮相,智能体验全面升级!

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

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

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

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

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

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

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

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

2026/7/20 0:01:04阅读更多 →
YOLOv8推理性能优化:从1.2FPS到35FPS的全链路加速实践

YOLOv8推理性能优化:从1.2FPS到35FPS的全链路加速实践

如果你在部署 YOLOv8 时,发现推理速度只有可怜的 1-2 FPS,而别人的演示视频却能跑到 30 FPS 以上,那么问题很可能不在模型本身,而在于你的整个处理链路。很多开发者拿到一个训练好的 YOLOv8 模型后,会直接使用官方示例…

2026/7/19 22:50:49阅读更多 →
Coze与Dify对比指南:低代码AI应用开发从入门到实战

Coze与Dify对比指南:低代码AI应用开发从入门到实战

1. 从零到一:为什么你需要了解 Coze 和 Dify?如果你对 AI 应用开发感兴趣,但一看到“大模型”、“智能体”、“工作流”这些词就头疼,觉得门槛太高,那这篇文章就是为你准备的。很多开发者,包括我自己&#…

2026/7/19 14:50:26阅读更多 →
AI生图工具怎么选?2026年6月版实测对比

AI生图工具怎么选?2026年6月版实测对比

做自媒体的朋友应该都有体会:配图一直是个让人头疼的问题。2026年,AI生图工具已经非常成熟了,但工具太多反而不知道怎么选。以下是截至2026年6月我对主流AI生图工具的实测对比。Midjourney V8.1:速度之王2026年6月11日&#xff0c…

2026/7/19 18:50:36阅读更多 →