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/29 13:16:59 阅读更多 →
042-Form Kit服务卡片

042-Form Kit服务卡片

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

2026/7/29 11:01:13 阅读更多 →
Android构建变体:Gradle多版本管理实战指南

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

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

2026/7/26 22:45:34 阅读更多 →

最新新闻

AI辅助学术写作:工具、实践与效率提升

AI辅助学术写作:工具、实践与效率提升

1. AI辅助学术写作的时代机遇去年协助一位语言学教授完成专著时,我们团队首次系统性地采用了AI写作工具。原本需要三个月完成的文献综述章节,最终仅用两周就达到了出版社的审稿标准。这个案例让我深刻意识到,学术写作正在经历从"笔耕不辍…

2026/7/30 4:01:35 阅读更多 →
大语言模型三大输出头解析:LM Head、条件生成头与价值头

大语言模型三大输出头解析:LM Head、条件生成头与价值头

如果你正在学习大语言模型(LLM)的内部原理,可能会被各种“头”(Head)的概念搞糊涂——语言建模头、条件生成头、价值头……这些听起来相似却又不同的组件,到底在模型中扮演什么角色?更重要的是&…

2026/7/30 4:01:35 阅读更多 →
小爱音箱改造:用大模型打造真智能语音助手

小爱音箱改造:用大模型打造真智能语音助手

1. 项目概述:为什么需要改造小爱音箱?家里的小爱同学用久了总会发现一些尴尬场景:问天气只能报官方数据,问菜谱只会念百度百科,讲笑话永远是那几个老梗。更糟心的是稍微复杂点的指令就回复"这个我还不会"——…

2026/7/30 4:01:35 阅读更多 →
ESP32原生USB CDC开发实战:告别串口芯片,实现高速稳定通信

ESP32原生USB CDC开发实战:告别串口芯片,实现高速稳定通信

1. 项目概述:为什么ESP32的USB CDC值得你花时间?如果你玩过Arduino ESP32,大概率用过它的串口打印功能,通过板载的USB转串口芯片(比如CP2102、CH340)和电脑通信。但你可能没意识到,这其实走了个…

2026/7/30 4:01:35 阅读更多 →
AI辅助学术写作:7款工具评测与查重降重技巧

AI辅助学术写作:7款工具评测与查重降重技巧

1. AI论文写作辅助工具的价值与现状作为一名在学术领域深耕多年的研究者,我深刻理解论文写作过程中的痛点。从文献综述到实验设计,从数据分析到论文撰写,每个环节都需要耗费大量时间精力。近年来AI技术的快速发展为学术写作带来了革命性变化&…

2026/7/30 4:01:35 阅读更多 →
STM32定时器PWM驱动电子琴:从GPIO输入到音频输出的嵌入式综合实践

STM32定时器PWM驱动电子琴:从GPIO输入到音频输出的嵌入式综合实践

1. 项目缘起:从按键到音符的跨越 很多朋友刚开始玩STM32,都是从点灯开始的,紧接着就是按键控制。当你熟练掌握了GPIO的输入输出,看着LED随着按键的按下而明灭,成就感是有的,但总觉得少了点意思——这和我们…

2026/7/30 4:00:34 阅读更多 →

日新闻

Windows驱动存储终极清理工具:DriverStoreExplorer完全指南

Windows驱动存储终极清理工具:DriverStoreExplorer完全指南

Windows驱动存储终极清理工具:DriverStoreExplorer完全指南 【免费下载链接】DriverStoreExplorer Driver Store Explorer 项目地址: https://gitcode.com/gh_mirrors/dr/DriverStoreExplorer 您是否曾因Windows系统盘空间不足而烦恼?是否遇到过设…

2026/7/30 0:00:13 阅读更多 →
如何3步掌握Video Download Helper:网页视频下载的完整实战指南

如何3步掌握Video Download Helper:网页视频下载的完整实战指南

如何3步掌握Video Download Helper:网页视频下载的完整实战指南 【免费下载链接】VideoDownloadHelper Chrome Extension to Help Download Video for Some Video Sites. 项目地址: https://gitcode.com/gh_mirrors/vi/VideoDownloadHelper 你是否曾经在浏览…

2026/7/30 0:00:13 阅读更多 →
“双减”后首个AI备课压力测试报告:覆盖32所中小学的176节AI辅助课,暴露4大隐性增负节点

“双减”后首个AI备课压力测试报告:覆盖32所中小学的176节AI辅助课,暴露4大隐性增负节点

更多请点击: https://intelliparadigm.com 第一章:AI 教师备课辅助 AI 教师备课辅助系统正逐步成为教育数字化转型的核心支撑工具,它并非替代教师,而是通过语义理解、知识图谱与多模态生成能力,将教师从重复性劳动中解…

2026/7/30 0:00:13 阅读更多 →

周新闻

深度学习道路桥梁裂缝检测系统 道路桥梁裂缝检测数据集 道路桥梁病害识别检测数据集

深度学习道路桥梁裂缝检测系统 道路桥梁裂缝检测数据集 道路桥梁病害识别检测数据集

深度学习道路桥梁裂缝检测系统 数据集6000张 完整源码已标注数据集训练好的模型环境配置教程程序运行说明文档,可以直接使用!系统支持图片、视频、摄像头等多种方式检测裂缝,功能强大实用。 1数据集6000张 8各类别

2026/7/29 22:18:20 阅读更多 →
深度学习YOLO模型如何训练 PUBG 绝地求生目标检测数据集

深度学习YOLO模型如何训练 PUBG 绝地求生目标检测数据集

pubg数据集 精选原图1.42万数据 1.49万标签 无任何重复、算法增强或冗余图像! pubg绝地求生目标检测数据集 1分类:e_body,14905个标签,txt格式 共计14244张图,99%为640*640尺寸图像 适合yolo目标检测、AI训练关键词&am…

2026/7/29 14:34:28 阅读更多 →
Apex英雄目标检测数据集 深度学习框架YOLO如何训练APEX数据集

Apex英雄目标检测数据集 深度学习框架YOLO如何训练APEX数据集

Apex检测数据集数据集详情检测类别: allies enemy tag图片总量:7247张训练集:5139张验证集:1425张测试集:683张标注状态:全部已标注,即拿即用数据格式:支持YOLO格式及其他格式&#…

2026/7/29 15:00:03 阅读更多 →

月新闻