【.NET开发必知】:委托不等于事件!你真的用对了吗?

.NET delegate 委托 、 Event 事件,接口回调,发布、订阅 另外,它还有两个 方法,分别是add_MakeGreet和remove_MakeGreet,这两个方法分别用于注册委 托类型的方法和取消注册。委托是一个类,它定义了方法的类型,使得可以将方法当作另一个方法的参数 来进行传递,这种将方法动态地赋给参数的做法,可以避免在程序中大量使用If-Else (Switch)语句,同时使得程序具有更好的可扩展性。在类的外部,注册“+=”和注 销“-=”的访问限定符与你在声明事件时使用的访问符相同。用”这个词,是因为此变量代表一个方法),可以依次调用所有绑定的方法。.... 阅读详情

第一章:委托与事件的本质解析

在 .NET 编程中,委托(Delegate)与事件(Event)是实现回调机制和松耦合设计的核心工具。它们不仅支撑着异步编程模型,也是 GUI 应用程序中响应用户操作的基础。

委托的定义与作用

委托是一种类型安全的函数指针,用于封装对具有特定参数列表和返回类型的方法的引用。通过委托,方法可以像对象一样被传递和调用。
// 定义一个委托,接受两个整数并返回整数
public delegate int MathOperation(int a, int b);

// 实现符合签名的方法
public static int Add(int a, int b) => a + b;

// 使用委托调用方法
MathOperation operation = Add;
int result = operation(5, 3); // 结果为 8
上述代码展示了如何定义和使用委托。委托使得方法可以在运行时动态绑定,增强了程序的灵活性。

事件的机制与应用场景

事件基于委托,提供了一种发布-订阅模式。类可以定义事件,其他类可注册事件处理器,在特定条件触发时执行相应逻辑。
  • 事件只能在声明它的类内部触发
  • 外部类只能进行订阅或取消订阅
  • 常用于按钮点击、数据变更通知等场景
特性委托事件
调用权限任意位置仅声明类内部可触发
赋值操作允许直接赋值不支持外部赋值
典型用途回调、策略模式通知、UI 响应
graph TD A[事件源] -->|触发| B(事件) B --> C[订阅者1] B --> D[订阅者2] C --> E[执行处理逻辑] D --> F[执行处理逻辑]

第二章:深入理解C#委托(Delegate)

2.1 委托的定义与底层机制剖析

委托(Delegate)是.NET中一种类型安全的函数指针,用于封装方法的引用。其本质是一个继承自`System.Delegate`的类,能够指向静态或实例方法。
委托的声明与实例化
public delegate int Calculator(int x, int y);

Calculator add = (a, b) => a + b;
int result = add(3, 4); // 返回 7
上述代码定义了一个名为`Calculator`的委托类型,可引用任意接受两个整型参数并返回整型的方法。Lambda表达式简化了方法绑定过程。
底层结构解析
每个委托实例包含两个关键字段:
  • Target:指向目标方法所属的对象实例(若为静态方法则为null)
  • Method:描述实际调用的方法元数据
当调用委托时,CLR通过Invoke方法触发底层方法调用,支持同步执行与异步回调(通过BeginInvoke/EndInvoke)。

2.2 委托链的构建与多播调用实践

在C#中,委托链通过组合多个委托实例形成调用列表,实现多播调用。使用 += 操作符可将方法附加到委托链,执行时按顺序调用所有注册的方法。
委托链的创建与调用
public delegate void NotifyHandler(string message);

NotifyHandler chain = null;
chain += LogMessage;
chain += SendMessage;

chain?.Invoke("系统事件触发");

void LogMessage(string msg) => Console.WriteLine($"日志: {msg}");
void SendMessage(string msg) => Console.WriteLine($"通知: {msg}");
上述代码中,NotifyHandler 委托类型定义了返回值为 void、参数为字符串的方法签名。通过 += 将两个方法加入委托链,调用时会依次执行日志记录与消息发送。
多播调用的特性分析
  • 调用顺序遵循注册顺序,不可逆序执行
  • 若某方法抛出异常,后续方法将不会执行
  • 可使用 GetInvocationList() 遍历并单独调用每个委托项,增强控制粒度

2.3 泛型委托Func、Action与Predicate的应用场景

在 .NET 开发中,`Func`、`Action` 与 `Predicate` 是三种常用的泛型委托,分别适用于不同的回调场景。
Func:带返回值的封装逻辑
`Func` 封装接收一个参数并返回特定类型结果的方法。常用于转换操作:
Func<int, int> square = x => x * x;
int result = square(5); // 返回 25
此处 `x` 为输入参数,表达式返回其平方值,适用于 LINQ 中的 Select 投影。
Action:执行无返回的操作
`Action` 用于不返回值的方法调用,如日志记录:
Action<string> log = msg => Console.WriteLine(msg);
log("用户登录");
该委托广泛应用于事件处理和异步回调。
Predicate:条件判断的简洁表达
`Predicate` 等价于 Func<T, bool>,专用于筛选条件:
  • 常用于 List.FindAll
  • 简化 LINQ 中的 Where 条件表达式

2.4 自定义委托类型的设计与性能考量

在高性能 .NET 应用开发中,合理设计自定义委托类型能显著提升代码可读性与执行效率。通过精简参数列表和避免装箱操作,可减少托管堆压力。
委托定义与泛型优化
public delegate TResult Func<T, TResult>(T arg);
该泛型委托封装了输入参数与返回值类型,编译期即可确定类型安全,避免运行时类型检查开销。
性能对比:自定义 vs 系统内置
委托类型调用耗时 (ns)GC 分配
CustomHandler120 B
EventHandler1832 B
设计建议
  • 优先使用泛型委托以消除装箱
  • 限制参数数量在三个以内以优化调用栈
  • 避免捕获闭包变量防止内存泄漏

2.5 委托在回调机制中的典型实战案例

在异步编程中,委托常被用于实现回调机制,使任务完成时能通知调用方。例如文件下载完成后触发数据处理。
事件完成后的回调处理

public delegate void DownloadCompletedHandler(string content);

public class FileDownloader
{
    public void DownloadAsync(string url, DownloadCompletedHandler callback)
    {
        // 模拟异步下载
        Task.Run(() =>
        {
            string data = "Downloaded content from " + url;
            callback?.Invoke(data); // 回调通知
        });
    }
}
上述代码定义了一个 DownloadCompletedHandler 委托,作为回调函数参数传入 DownloadAsync 方法。当下载完成,自动执行回调,实现解耦。
应用场景优势
  • 提升模块间松耦合性
  • 支持动态行为注入
  • 简化异步结果处理流程

第三章:事件(Event)的核心原理与使用

3.1 事件的封装性与访问限制机制

在现代系统设计中,事件的封装性确保了数据的一致性和安全性。通过将事件定义为不可变对象,仅暴露必要的属性和方法,可有效防止外部误操作。
访问控制策略
采用权限层级控制事件的发布与订阅:
  • 私有事件:仅限同一模块内触发与监听
  • 受保护事件:允许子系统订阅,但不可伪造
  • 公开事件:跨服务传播,需签名验证
代码实现示例
type UserCreatedEvent struct {
    UserID    string `json:"user_id"`
    Timestamp int64  `json:"timestamp"`
    // 私有字段,禁止外部直接修改
    source string
}

func NewUserCreatedEvent(id string) *UserCreatedEvent {
    return &UserCreatedEvent{
        UserID:    id,
        Timestamp: time.Now().Unix(),
        source:    "user-service",
    }
}
上述代码通过构造函数初始化事件,并隐藏内部字段 source,保证事件来源可信。字段不可变性由构造函数初始化后锁定,符合封装原则。

3.2 基于EventHandler标准模式的事件设计

在 .NET 生态中,EventHandler 模式是事件驱动编程的核心范式,通过委托机制实现发布-订阅模型。
事件定义与标准签名
遵循约定,事件处理方法应接收两个参数:发送者对象和继承自 EventArgs 的数据类。
public delegate void DataProcessedEventHandler(object sender, DataProcessedEventArgs e);
public class DataProcessedEventArgs : EventArgs {
    public string Status { get; set; }
}
其中,sender 提供事件源引用,e 封装自定义事件数据,便于跨组件通信。
事件发布与订阅流程
使用 event 关键字声明事件成员,确保封装性:
  • 定义事件:public event DataProcessedEventHandler DataProcessed;
  • 触发事件:OnDataProcessed 方法中检查空引用后调用
  • 外部订阅:+= 注册回调函数,-= 移除监听

3.3 事件在松耦合架构中的应用实例

订单处理系统中的事件驱动设计
在电商系统中,订单创建后需触发库存扣减、物流调度和用户通知。通过事件机制,各服务无需直接调用,实现解耦。
// 发布订单创建事件
type OrderCreatedEvent struct {
    OrderID    string
    ProductID  string
    Quantity   int
}

func (s *OrderService) CreateOrder(order Order) {
    // 保存订单
    repo.Save(order)
    // 发布事件
    eventBus.Publish(&OrderCreatedEvent{
        OrderID:   order.ID,
        ProductID: order.ProductID,
        Quantity:  order.Quantity,
    })
}
上述代码中,订单服务仅负责发布事件,不感知下游逻辑。库存、物流等服务通过订阅该事件自行处理,提升系统可维护性与扩展性。
事件通信的优势体现
  • 服务间无直接依赖,可独立部署与演进
  • 支持异步处理,提高响应性能
  • 便于监控与重试机制的集中管理

第四章:委托与事件的关键差异与最佳实践

4.1 访问权限对比:谁可以触发?谁可以订阅?

在事件驱动架构中,访问权限的划分直接影响系统的安全性和可维护性。触发(Publish)与订阅(Subscribe)作为两个核心操作,其权限控制策略需明确区分。
角色权限模型
通常系统会定义三类角色:
  • 生产者:具备事件触发权限
  • 消费者:仅允许订阅和消费事件
  • 管理员:管理主题与权限分配
权限控制示例
type EventPermission struct {
    Topic      string   `json:"topic"`
    Publishers []string `json:"publishers"` // 允许发布的角色列表
    Subscribers []string `json:"subscribers"` // 允许订阅的角色列表
}
该结构体定义了每个主题的访问白名单,通过角色名限制发布与订阅行为,确保最小权限原则。
权限对比表
角色可触发可订阅
生产者✓✗
消费者✗✓
管理员✓✓

4.2 内存管理与事件泄漏的规避策略

在现代前端应用中,内存管理直接影响运行效率。未正确释放事件监听器或定时任务将导致内存泄漏,拖慢页面性能。
常见泄漏场景
  • DOM 元素移除后仍保留事件监听
  • 闭包引用外部大对象未释放
  • setInterval 未 clearTimeout
事件监听的正确销毁
const handler = () => console.log('click');
document.addEventListener('click', handler);
// 组件卸载时
document.removeEventListener('click', handler);
使用具名函数确保可解绑,匿名函数无法有效移除。
WeakMap 优化对象引用
数据结构键类型支持垃圾回收
Map任意不自动回收
WeakMap对象自动回收
WeakMap 键为弱引用,避免因缓存导致的内存堆积。

4.3 在WPF/WinForms中事件的实际运用分析

在WPF与WinForms开发中,事件机制是实现用户交互的核心。通过订阅控件的事件(如点击、输入、加载),开发者可以响应用户操作并驱动界面逻辑。
事件绑定示例
button1.Click += (sender, e) =>
{
    MessageBox.Show("按钮被点击!");
};
该代码为按钮的Click事件注册匿名处理方法。sender表示触发事件的对象,e为事件参数。Lambda表达式简化了事件绑定逻辑,提升代码可读性。
事件传递与冒泡
WPF支持路由事件,允许事件在元素树中向上冒泡。例如,Button点击可被其父Panel捕获:
  • 事件源触发事件
  • 沿可视化树向上传递
  • 上级容器可监听并处理
常见事件对比
控件常用事件用途
TextBoxTextChanged实时响应输入变化
ComboBoxSelectionChanged选项变更时更新界面

4.4 如何选择:何时用委托,何时必须用事件?

在 .NET 编程中,委托和事件都基于相同的底层机制,但用途和语义存在关键差异。
使用委托的场景
当需要传递方法引用或实现回调机制时,委托是理想选择。例如:
public delegate void Logger(string message);
public void Process(Logger log) {
    log("处理开始");
}
该代码定义了一个日志回调委托,允许调用方自定义日志行为,适用于松耦合的函数注入。
必须使用事件的场景
事件用于发布-订阅模式,强调“通知”。它提供封装性,防止外部类触发事件:
public event EventHandler<DataEventArgs> DataReceived;
protected virtual void OnDataReceived(DataEventArgs e) {
    DataReceived?.Invoke(this, e);
}
此处 DataReceived 事件只能由类内部触发,确保封装安全,适用于跨组件通信。
  • 用委托:方法回调、策略模式
  • 用事件:状态变更通知、UI交互响应

第五章:结语:掌握本质,写出更安全的.NET代码

理解类型系统与内存管理
.NET 的公共语言运行时(CLR)通过自动垃圾回收和类型安全机制大幅降低了内存泄漏和非法访问风险。开发者应深入理解值类型与引用类型的差异,避免在高频操作中频繁分配临时对象。
  • 优先使用 struct 存储小型、生命周期短的数据结构
  • 避免在循环中创建 IDisposable 对象而不显式释放
防范常见安全漏洞
输入验证不足是多数安全问题的根源。以下代码展示了如何使用参数化查询防止 SQL 注入:

using (var connection = new SqlConnection(connectionString))
{
    var command = new SqlCommand(
        "SELECT * FROM Users WHERE Username = @username", connection);
    command.Parameters.AddWithValue("@username", userInput); // 参数化防止注入
    connection.Open();
    var reader = command.ExecuteReader();
}
利用代码分析工具提升质量
启用 Roslyn 分析器可在编译期捕获潜在缺陷。推荐配置:
工具用途启用方式
Microsoft.CodeAnalysis.FxCopAnalyzers检测安全与性能问题NuGet 包安装并启用规则集
StyleCop.Analyzers统一代码风格项目引入后自动生效
实施最小权限原则
应用程序应在最低必要权限下运行。例如,Web 应用不应以 SYSTEM 账户启动。使用 AppPoolIdentity 配合 Code Access Security(CAS)策略可有效限制攻击面。
.NET中委托的性能演变 阅读详情

相关推荐

C#中的委托与事件详解

委托(Delegate)是C#中的一种类型,用于引用具有特定参数列表和返回类型的方法,本质上是一种类型安全的函数指针。它允许将方法作为参数传递、存储在变量中或从方法返回。委托支持多播,可以组合多个方法,并且是.NET事件模型的基础。C#中常用的内置委托类型包括Action、Func和Predicate,分别用于无返回值、有返回值和返回布尔值的方法。 事件(Event)是建立在委托基础上的高级特性,用于实现观察者模式(发布-订阅模型)。事件封装了委托,限制外部只能通过+=和-=操作订阅或取消订阅,提供了更安全

记录学习的过程 1305

.Net学习——委托

委托(Delegate)类似于 C 或 C++ 中函数的指针。委托(Delegate) 是存有对某个方法的引用的一种引用类型变量。引用可在运行时被改变。调用委托变量时,就是执行该变量指向的方法。委托与c#中的普通变量【如int i=5】类似,唯一区别在于委托指向方法,普通变量执向整数为5的空间委托声明决定了可由该委托引用的方法。委托可指向一个与其具有相同标签的方法。关键字 返回类型 委托的名称 参数列表。

contact97的博客 3391

.Net委托详解

委托是.NET中一个非常有用的特性,它提供了回调方法、事件处理等多种用途的实现机制。理解并熟练使用委托,可以使代码更加灵活和强大。

Code365 535

【.NET Core】委托(Delegate)应用详解

委托(Delegate)是存有对某个方法的引用的一种引用类型变量。引用可在运行时被改变。委托(Delegate)类似于C或C++中函数指针。委托是将方法调用者和目标方法动态关联起来,委托是一个类,实质上是一个类,可以通过委托隐藏方法,虽然委托定义方法的参数及其返回值,但是它并不是和方法一个层级的。委托(Delegate)可以将方法当作另一个方法的参数来进行传递,这种方法动态地赋给参数的做法,可以避免在程序中大量使用If-Else(Switch)语句,同时使得程序具有更好的可扩展性。delegate。

记录总结工作过往 3093

VB.NET事件委托与多控件共享事件处理实战教程

委托是一种类型,它定义了引用方法的签名。它类似于C或C++中的函数指针的概念,但比函数指针更安全和更具有面向对象的特性。委托类型的变量可以引用具有匹配签名的任何方法,无论是实例方法还是静态方法。在事件处理的上下文中,委托通常被用来引用事件处理程序。事件是委托的一种特殊形式,它允许一个或多个方法被注册到事件源(如控件),在事件被触发时,这些方法将被执行。因此,委托在事件中起到了一个“中间人”的角色,使得事件源和事件处理程序能够相互通信。

weixin_35835018的博客 934

深入理解.NET中的主持人委托事件

本文还有配套的精品资源,点击获取 简介:在.NET编程领域中,“主持人委托事件”是一个关键概念,特别是在设计模式和事件驱动编程中发挥重要作用。委托允许方法作为参数传递,实现函数回调或事件处理功能。本实践项目将深入探讨如何在C#中定义和使用委托、事件,并展示不同类之间的事件通信。开发者将通过阅读和分析项目代码,掌握事件驱动编程的工作原理和最佳实践,提升应用程序的交互性和响应性...

weixin_35879493的博客 730

技术讲座:.NET委托、事件及应用兼谈软件项目开发

ODY, P, TD { font-family: Verdana, Arial, Helvetica, sans-serif; font-size: 10pt }H2,H3,H4,H5 { color: #0000FF; font-weight: bold; }H2 { font-size: 13pt; }H3 { font-size: 12pt; }H4 { font-si

HuLihui's Blog 7765

【5G NB-IoT NTN】3GPP R17 NB-IoT NTN介绍_nbiot ntn

你的支持,我的动力;祝各位前程似锦,offer不断,步步高升!!!” />你的支持,我的动力;祝各位前程似锦,offer不断,步步高升!!!更多资料点击此处获qu!!

2401_83703866的博客 3166

vb.net中的委托与事件

委托是CTS(公共类型系统)规定的5种类型之一(类类型、结构类型、接口类型、枚举类型、委托类型)它是一种类型可以用来调用其他对象的方法,也称为函数指针。其实在vb.net中委托也可以当做是可以用来共享其他对象的方法的对象。当程序必须通过调用一个方法来执行某个操作(调用某个方法),但在编译时不知道该方法是什么时,就可以使用委托。委托允许在程序运行时指定调用的方法,委托的特点是面向对象的,类型是安全的

不忘初心 ,方得始终 1万+

Keil MDK安装NRF52832开发环境全攻略(附系统时间错误解决方案)

本文详细介绍了如何使用Keil MDK搭建NRF52832开发环境,包括基础软件安装、项目配置关键步骤以及常见问题解决方案。特别针对系统时间错误导致的编译失败问题提供了实用解决方法,帮助开发者快速上手NRF52832开发。

weixin_29168153的博客 505

ADS交叉耦合振荡器VCO仿真

本文主要参考视频中如何使用进行ADS交叉耦合振荡器仿真和分析,由于视频中有诸多错误和视频清晰度较低,虽然视频博主及时改正,为了节省学习时间,可以直接参考本文。

qq_32589131的博客 5425

事件与委托

事件(Event)和委托(Delegate)都是用于实现对象间通信的机制。事件和委托是.NET框架中用于实现类型安全、多播和动态方法引用的机制,支持异步编程和回调,促进了解耦和组件间的松散耦合,广泛应用于UI编程、数据绑定和异步操作,并在C#等语言中通过语法糖提供简洁易用的编码体验。其中事件使用委托来定义可以被调用的方法的签名,它们只允许具有正确签名的方法与之关联,这也是他们类型安全的体现。我在企业开发中发现公司更多用动作委托(Action)来替代需要使用委托的地方,所以本文还将简单描述一下动作委托。

qq_47159522的博客 1995

Android编译系统——Android.bp语法介绍(十五)

Android.bp 是 Android 构建系统(Android Build System)中的配置文件,用于描述如何编译和打包项目中的模块。它是用 Blueprint 编写的,其语法类似于 JSON,但专为 Android 编译系统设计,提供了更高效、灵活的模块化管理。

小旭的专栏 939

【.net6第二章】委托与事件

委托是一种引用类型,表示对具有特定参数列表和返回类型的方法的引用。在实例化委托时,你可以将其实例与任何具有兼容签名和返回类型的方法相关联。跟方法有点类似,有参数有返回值,拥有关键字delegate,是一种特殊的访问。委托的本质是个一个类,继承自特殊类MulticastDelegate(无法继承),MulticastDelegate继承自Delegate类。委托可以通过new实例化,要求传递一个和这个委托的参数和返回值完全匹配的方法。//初始化关联信息//学校公告发布者Id = 111,

CZ_TyT的博客 2595

昇腾,Ascend,NPU,mindie,镜像,部署vllm:第5篇,昇腾环境下部署蒸馏版deepseek-r1,并在dify中注册模型供应商

这两天没少折腾deepseek-r1。之前在A100上用ollama部署了一份DeepSeek-R1-Distill-Qwen-32B,感觉真的特别慢。现在,再用昇腾部署一遍,看看速度能不能更快。p.s. 类似的内容其实已经写了很多遍了。但感觉之前写得都太碎,不够顺畅。接着新模型写篇长文,把能包括的都包括进来。这样大家也不需要到处翻来翻去。

xiezhipu的博客 2450

24、手机GPS天线设计与有源GNSS天线性能评估

本文系统介绍了手机GPS天线的代表性设计,包括隔离磁偶极子、共面平衡偶极子和小型陶瓷加载QHA天线,分析了其结构特点、性能参数及适用场景。同时详细阐述了有源GNSS天线的组成结构与G/T比作为关键性能指标的评估方法,并提出了组件选择、噪声控制和增益提升等优化策略。最后展望了未来手机GPS天线在小型化、多频集成和智能适应性方面的发展趋势。

pytorch8learner的博客 720

.net 中委托与事件的理解!

假如我定义了这样一个委托:public  delegate void Feedback(object sender,EventArgs e);注意,如果没有学习过委托,看这句代码好象只是一个函数,其实这句话真正的用意是定义一个委托类型,如果你了解他在.net框架里面的具体形式,完全可以这样写: public class Feedback:System.MulticastDelagate{//构造器

lyb_abiandbel的专栏 3353

宇树科技嵌入式面试题及参考答案(春晚机器人的公司)

内存对齐是指在内存中为数据对象分配存储空间时,按照一定的规则将数据存储在特定的地址上,以提高内存访问效率。不同的数据类型在内存中都有其特定的对齐要求,例如,int类型通常要求 4 字节对齐,double类型通常要求 8 字节对齐。这意味着数据的存储地址必须是其对齐字节数的整数倍。如果不进行内存对齐,处理器在访问数据时可能需要进行多次内存访问,从而降低了访问效率。指令可以用于控制结构体内存布局,它允许程序员指定结构体成员的对齐方式。其基本用法是在结构体定义之前使用来指定对齐字节数n,其中n。

大模型大数据攻城狮的专栏 3226

C#.Net筑基-解密委托与事件

委托是一种用来包装方法的特殊类型,可以将方法包装为对象进行传递、调用,类似函数指针。delegate关键字用来定义一个委托类型,语法类似方法申明,可以看做是一个“方法签名模板”,和方法一样定义了方法的返回值、参数。用delegate定义的委托是一个类,继承自 System.MulticastDelegate、System.Delegate,“方法名”就是委托类型的名称。委托的使用同其他普通类型,实例指向一个方法的引用,该方法的申明和委托定义的“方法签名模板”须匹配(支持协变逆变。

李赛赛的专栏 1472

【图论】系列(七)图论的中心性度量方法及重要性评价指标

图论中的中心性度量方法是用来衡量图中各个节点(或顶点)相对重要性的指标。

qq_30066733的博客 1077

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

VB.NET下的事件和委托

委托是可用于调用其他对象方法的对象。它们有时被称为类型安全函数指针,因为它们与其他编程语言中所使用的函数指针相似。但不同于函数指针,Visual Basic .NET 委托是基于System.Delegate类的引用类型,它可以引用共享方法 —无需特定的类实例即可调用的方法和实例方法。 委托在调用过程和被调用过程需要媒介的情况下是很有用的。例如,您可能想让一个引发事件的对象能够在不同的环境下...

阿亮的专栏 1482

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

微软.NET6开发的C#特性——委托和事件

微软.NET6开发的C#特性——委托和事件

荔园微风的博客 2325

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

深度学习工具包 DeepLearningToolbox

深度学习工具包Deprecation notice.-----This toolbox is outdated and no longer maintained.There are much better tools available for deep learning than this toolbox, e.g. [Theano](http://deeplearning.net/software/theano/), [torch](http://torch.ch/) or [tensorflow](http://www.tensorflow.org/)I would suggest you use one of the tools mentioned above rather than use this toolbox.Best, Rasmus.DeepLearnToolbox================A Matlab toolbox for Deep Learning.Deep Learning is a new subfield of machine learning that focuses on learning deep hierarchical models of data.It is inspired by the human brain's apparent deep (layered, hierarchical) architecture.A good overview of the theory of Deep Learning theory is[Learning Deep Architectures for AI](http://www.iro.umontreal.ca/~bengioy/papers/ftml_book.pdf)For a more informal introduction, see the following videos by Geoffrey Hinton and Andrew Ng.* [The Next Generation of Neural Networks](http://www.youtube.com/watch?v=AyzOUbkUf3M) (Hinton, 2007)* [Recent Developments in Deep Learning](http://www.youtube.com/watch?v=VdIURAu1-aU) (Hinton, 2010)* [Unsupervised Feature Learning and Deep Learning](http://www.youtube.com/watch?v=ZmNOAtZIgIk) (Ng, 2011)If you use this toolbox in your research please cite [Prediction as a candidate for learning deep hierarchical models of data](http://www2.imm.dtu.dk/pubdb/views/publication_details.php?id=6284)```@MASTERSTHESIS\{IMM2012-06284, author = "R. B. Palm", title = "Prediction as a candidate for learning deep hierarchical models of data", year = "2012",}```Contact: rasmusbergpalm at gmail dot comDirectories included in the toolbox-----------------------------------`NN/` - A library for Feedforward Backpropagation Neural Networks`CNN/` - A library for Convolutional Neural Networks`DBN/` - A library for Deep Belief Networks`SAE/` - A library for Stacked Auto-Encoders`CAE/` - A library for Convolutional Auto-Encoders`util/` - Utility functions used by the libraries`data/` - Data used by the examples`tests/` - unit tests to verify toolbox is workingFor references on each library check REFS.mdSetup-----1. Download.2. addpath(genpath('DeepLearnToolbox'));Example: Deep Belief Network---------------------```matlabfunction test_example_DBNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit RBM and visualize its weightsrand('state',0)dbn.sizes = [100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);figure; visualize(dbn.rbm{1}.W'); % Visualize the RBM weights%% ex2 train a 100-100 hidden unit DBN and use its weights to initialize a NNrand('state',0)%train dbndbn.sizes = [100 100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);%unfold dbn to nnnn = dbnunfoldtonn(dbn, 10);nn.activation_function = 'sigm';%train nnopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.10, 'Too big error');```Example: Stacked Auto-Encoders---------------------```matlabfunction test_example_SAEload mnist_uint8;train_x = double(train_x)/255;test_x = double(test_x)/255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit SDAE and use it to initialize a FFNN% Setup and train a stacked denoising autoencoder (SDAE)rand('state',0)sae = saesetup([784 100]);sae.ae{1}.activation_function = 'sigm';sae.ae{1}.learningRate = 1;sae.ae{1}.inputZeroMaskedFraction = 0.5;opts.numepochs = 1;opts.batchsize = 100;sae = saetrain(sae, train_x, opts);visualize(sae.ae{1}.W{1}(:,2:end)')% Use the SDAE to initialize a FFNNnn = nnsetup([784 100 10]);nn.activation_function = 'sigm';nn.learningRate = 1;nn.W{1} = sae.ae{1}.W{1};% Train the FFNNopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.16, 'Too big error');```Example: Convolutional Neural Nets---------------------```matlabfunction test_example_CNNload mnist_uint8;train_x = double(reshape(train_x',28,28,60000))/255;test_x = double(reshape(test_x',28,28,10000))/255;train_y = double(train_y');test_y = double(test_y');%% ex1 Train a 6c-2s-12c-2s Convolutional neural network %will run 1 epoch in about 200 second and get around 11% error. %With 100 epochs you'll get around 1.2% errorrand('state',0)cnn.layers = { struct('type', 'i') %input layer struct('type', 'c', 'outputmaps', 6, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %sub sampling layer struct('type', 'c', 'outputmaps', 12, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %subsampling layer};cnn = cnnsetup(cnn, train_x, train_y);opts.alpha = 1;opts.batchsize = 50;opts.numepochs = 1;cnn = cnntrain(cnn, train_x, train_y, opts);[er, bad] = cnntest(cnn, test_x, test_y);%plot mean squared errorfigure; plot(cnn.rL);assert(er<0.12, 'Too big error');```Example: Neural Networks---------------------```matlabfunction test_example_NNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);% normalize[train_x, mu, sigma] = zscore(train_x);test_x = normalize(test_x, mu, sigma);%% ex1 vanilla neural netrand('state',0)nn = nnsetup([784 100 10]);opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samples[nn, L] = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.08, 'Too big error');%% ex2 neural net with L2 weight decayrand('state',0)nn = nnsetup([784 100 10]);nn.weightPenaltyL2 = 1e-4; % L2 weight decayopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex3 neural net with dropoutrand('state',0)nn = nnsetup([784 100 10]);nn.dropoutFraction = 0.5; % Dropout fraction opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex4 neural net with sigmoid activation functionrand('state',0)nn = nnsetup([784 100 10]);nn.activation_function = 'sigm'; % Sigmoid activation functionnn.learningRate = 1; % Sigm require a lower learning rateopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex5 plotting functionalityrand('state',0)nn = nnsetup([784 20 10]);opts.numepochs = 5; % Number of full sweeps through datann.output = 'softmax'; % use softmax outputopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex6 neural net with sigmoid activation and plotting of validation and training error% split training data into training and validation datavx = train_x(1:10000,:);tx = train_x(10001:end,:);vy = train_y(1:10000,:);ty = train_y(10001:end,:);rand('state',0)nn = nnsetup([784 20 10]); nn.output = 'softmax'; % use softmax outputopts.numepochs = 5; % Number of full sweeps through dataopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, tx, ty, opts, vx, vy); % nntrain takes validation set as last two arguments (optionally)[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');```[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/rasmusbergpalm/deeplearntoolbox/trend.png)](https://bitdeli.com/free "Bitdeli Badge")

C# .Net 委托和事件的区别

   在.net中,事件是一种特殊的委托,那他到底特殊在哪,换句话说,加上event关键字到底有什么用,我理解主要有两方面,下面用实例说明:    一 、事件只能在本类型内部“触发”,委托不管在本类型内部还是外部都可以“调用”。   举个例子,按钮的Click事件只有在鼠标点击按钮才能触发,没有例外;但如果Click是委托的话,我可以通过代码直接调用这个委托,就可以使得Click事件中

azkaser的专栏 1万+

.net----委托和事件

在事件生产者类中添加有关发生事件的代码,即当满足某种条件时(发生事件),则调用委托,即调用多播事件委托实例封装的调用列表中添加的事件处理方法。每一个值参数(没有 ref 或 out 修饰符的参数)都存在从D中的参数类型到M中的对应参数类型的标识或隐式引用转换。通过“+=”向多播事件委托实例封装的调用列表中添加事件处理方法,或通过“-=”从多播事件委托实例封装的调用列表中删除事件处理方法;在事件生产者类中声明一个事件成员,即某种事件处理委托(简称为事件委托)的实例(多播事件委托实例);

醉卧考场君莫笑 1881
上一篇: C++17中std::any使用全攻略(从入门到精通必读)
下一篇: 为什么你的协程不生效?7大IEnumerator使用误区全解析
PixelFlow
博客等级 码龄1年 180粉丝 2207原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值