是否有必要在 C# 中显式删除事件处理程序

2023-12-05

我有一堂课提供一些活动。该类是全局声明的,但不是在该全局声明上实例化的——它是根据需要在需要它的方法中实例化的。

每次方法中需要该类时,都会对其进行实例化并注册事件处理程序。在方法超出范围之前是否有必要显式删除事件处理程序?

当方法超出范围时,类的实例也会超出范围。将事件处理程序注册到超出范围的实例是否会产生内存占用? (我想知道事件处理程序是否阻止 GC 将类实例视为不再被引用。)


就你而言,一切都很好。这是一个物体出版保持的事件targets事件处理程序的实时状态。所以如果我有:

publisher.SomeEvent += target.DoSomething;

then publisher有参考target但反之则不然。

在您的情况下,发布者将有资格进行垃圾收集(假设没有其他对它的引用),因此它具有对事件处理程序目标的引用这一事实是无关紧要的。

棘手的情况是当发布者寿命很长但订阅者不想加入时that如果您需要取消订阅处理程序。例如,假设您有一些数据传输服务,可以让您订阅有关带宽更改的异步通知,并且传输服务对象是长期存在的。如果我们这样做:

BandwidthUI ui = new BandwidthUI();
transferService.BandwidthChanged += ui.HandleBandwidthChange;
// Suppose this blocks until the transfer is complete
transferService.Transfer(source, destination);
// We now have to unsusbcribe from the event
transferService.BandwidthChanged -= ui.HandleBandwidthChange;

(您实际上想要使用finally块来确保不会泄漏事件处理程序。)如果我们没有取消订阅,那么BandwidthUI至少会和接送服务一样长。

就我个人而言,我很少遇到这种情况 - 通常,如果我订阅一个事件,该事件的目标至少与发布者一样长 - 例如,表单将与其上的按钮一样长。了解这个潜在问题是值得的,但我认为有些人在不必要的时候会担心它,因为他们不知道引用的方向。

EDIT:这是对乔纳森·狄金森评论的回应。首先,查看文档委托.Equals(对象)这清楚地给出了平等行为。

其次,这是一个简短但完整的程序来显示取消订阅的工作原理:

using System;

public class Publisher
{
    public event EventHandler Foo;

    public void RaiseFoo()
    {
        Console.WriteLine("Raising Foo");
        EventHandler handler = Foo;
        if (handler != null)
        {
            handler(this, EventArgs.Empty);
        }
        else
        {
            Console.WriteLine("No handlers");
        }
    }
}

public class Subscriber
{
    public void FooHandler(object sender, EventArgs e)
    {
        Console.WriteLine("Subscriber.FooHandler()");
    }
}

public class Test
{
    static void Main()
    {
         Publisher publisher = new Publisher();
         Subscriber subscriber = new Subscriber();
         publisher.Foo += subscriber.FooHandler;
         publisher.RaiseFoo();
         publisher.Foo -= subscriber.FooHandler;
         publisher.RaiseFoo();
    }
}

Results:

Raising Foo
Subscriber.FooHandler()
Raising Foo
No handlers

(在 Mono 和 .NET 3.5SP1 上测试。)

进一步编辑:

这是为了证明事件发布者可以在仍然存在对订阅者的引用的情况下被收集。

using System;

public class Publisher
{
    ~Publisher()
    {
        Console.WriteLine("~Publisher");
        Console.WriteLine("Foo==null ? {0}", Foo == null);
    }

    public event EventHandler Foo;
}

public class Subscriber
{
    ~Subscriber()
    {
        Console.WriteLine("~Subscriber");
    }

    public void FooHandler(object sender, EventArgs e) {}
}

public class Test
{
    static void Main()
    {
         Publisher publisher = new Publisher();
         Subscriber subscriber = new Subscriber();
         publisher.Foo += subscriber.FooHandler;

         Console.WriteLine("No more refs to publisher, "
             + "but subscriber is alive");
         GC.Collect();
         GC.WaitForPendingFinalizers();         

         Console.WriteLine("End of Main method. Subscriber is about to "
             + "become eligible for collection");
         GC.KeepAlive(subscriber);
    }
}

结果(在 .NET 3.5SP1 中;Mono 在这里表现得有点奇怪。稍后会研究一下):

No more refs to publisher, but subscriber is alive
~Publisher
Foo==null ? False
End of Main method. Subscriber is about to become eligible for collection
~Subscriber
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

是否有必要在 C# 中显式删除事件处理程序 的相关文章

  • C 编程 - 文件 - fwrite

    我有一个关于编程和文件的问题 while current NULL if current gt Id Doctor 0 current current gt next id doc current gt Id Doctor if curre
  • 没有强命名的代码签名是否会让您的应用程序容易被滥用?

    尝试了解authenticode代码签名和强命名 我是否正确地认为 如果我对引用一些 dll 非强命名 的 exe 进行代码签名 恶意用户就可以替换我的 DLL 并以看似由我签名但正在运行的方式分发应用程序他们的代码 假设这是真的 那么您似
  • GLKit的GLKMatrix“列专业”如何?

    前提A 当谈论线性存储器中的 列主 矩阵时 列被一个接一个地指定 使得存储器中的前 4 个条目对应于矩阵中的第一列 另一方面 行主 矩阵被理解为依次指定行 以便内存中的前 4 个条目指定矩阵的第一行 A GLKMatrix4看起来像这样 u
  • Web 客户端和 Expect100Continue

    使用 WebClient C NET 时设置 Expect100Continue 的最佳方法是什么 我有下面的代码 我仍然在标题中看到 100 continue 愚蠢的 apache 仍然抱怨 505 错误 string url http
  • 动态加载程序集的应用程序配置

    我正在尝试将模块动态加载到我的应用程序中 但我想为每个模块指定单独的 app config 文件 假设我的主应用程序有以下 app config 设置
  • 嵌套接口:将 IDictionary> 转换为 IDictionary>?

    我认为投射一个相当简单IDictionary
  • 使用实体框架模型输入安全密钥

    这是我今天的完美想法 Entity Framework 中的强类型 ID 动机 比较 ModelTypeA ID 和 ModelTypeB ID 总是 至少几乎 错误 为什么编译时不处理它 如果您使用每个请求示例 DbContext 那么很
  • 类模板参数推导 - clang 和 gcc 不同

    下面的代码使用 gcc 编译 但不使用 clang 编译 https godbolt org z ttqGuL template
  • Clang 3.1 + libc++ 编译错误

    我已经构建并安装了 在前缀下 alt LLVM Clang trunk 2012 年 4 月 23 日 在 Ubuntu 12 04 上成功使用 GCC 4 6 然后使用此 Clang 构建的 libc 当我想使用它时我必须同时提供 lc
  • 关于 C++ 转换:参数 1 从“[some_class]”到“[some_class]&”没有已知的转换

    我正在研究 C 并且遇到了一个错误 我不知道确切的原因 我已经找到了解决方案 但仍然想知道原因 class Base public void something Base b int main Base b b something Base
  • C#中如何移动PictureBox?

    我已经使用此代码来移动图片框pictureBox MouseMove event pictureBox Location new System Drawing Point e Location 但是当我尝试执行时 图片框闪烁并且无法识别确切
  • WCF 中 SOAP 消息的数字签名

    我在 4 0 中有一个 WCF 服务 我需要向 SOAP 响应添加数字签名 我不太确定实际上应该如何完成 我相信响应应该类似于下面的链接中显示的内容 https spaces internet2 edu display ISWG Signe
  • 显示UnityWebRequest的进度

    我正在尝试使用下载 assetbundle统一网络请求 https docs unity3d com ScriptReference Networking UnityWebRequest GetAssetBundle html并显示进度 根
  • 使用 Bearer Token 访问 IdentityServer4 上受保护的 API

    我试图寻找此问题的解决方案 但尚未找到正确的搜索文本 我的问题是 如何配置我的 IdentityServer 以便它也可以接受 授权带有 BearerTokens 的 Api 请求 我已经配置并运行了 IdentityServer4 我还在
  • 如何序列化/反序列化自定义数据集

    我有一个 winforms 应用程序 它使用强类型的自定义数据集来保存数据进行处理 它由数据库中的数据填充 我有一个用户控件 它接受任何自定义数据集并在数据网格中显示内容 这用于测试和调试 为了使控件可重用 我将自定义数据集视为普通的 Sy
  • 向现有 TCP 和 UDP 代码添加 SSL 支持?

    这是我的问题 现在我有一个 Linux 服务器应用程序 使用 C gcc 编写 它与 Windows C 客户端应用程序 Visual Studio 9 Qt 4 5 进行通信 是什么very在不完全破坏现有协议的情况下向双方添加 SSL
  • 通过指向其基址的指针删除 POD 对象是否安全?

    事实上 我正在考虑那些微不足道的可破坏物体 而不仅仅是POD http en wikipedia org wiki Plain old data structure 我不确定 POD 是否可以有基类 当我读到这个解释时is triviall
  • 混合 ExecutionContext.SuppressFlow 和任务时 AsyncLocal.Value 出现意外值

    在应用程序中 由于 AsyncLocal 的错误 意外值 我遇到了奇怪的行为 尽管我抑制了执行上下文的流程 但 AsyncLocal Value 属性有时不会在新生成的任务的执行范围内重置 下面我创建了一个最小的可重现示例来演示该问题 pr
  • C++ 中类级 new 删除运算符的线程安全

    我在我的一门课程中重新实现了新 删除运算符 现在我正在使我的代码成为多线程 并想了解这些运算符是否也需要线程安全 我在某处读到 Visual Studio 中默认的 new delete 运算符是线程安全的 但这对于我的类的自定义 new
  • 对来自流读取器的过滤数据执行小计

    编辑问题未得到解答 我有一个基于 1 个标准的过滤输出 前 3 个数字是 110 210 或 310 给出 3 个不同的组 从流阅读器控制台 问题已编辑 因为第一个答案是我给出的具体示例的字面解决方案 我使用的实际字符串长度为 450 个

随机推荐

  • 安装cordova时卡住了

    我正在按照cordova主页上的步骤操作 但第一步我很困惑 我输入了sudo npm install g cordova在终端 但它卡住了 loadDep Xtend 网络 这需要几个小时 但没有进一步的进展 实际上 我在中国 我想这可能是
  • Java Web 应用程序。春季启动。定位图像

    我最近解决了在这个社区中定位图像的问题 你可以看here 然而 有一个答案说 您的应用程序是 Spring Boot 应用程序 我认为您还可以尝试使用 Spring Boot 提供的设施来提供静态内容 不管怎样 你现在正在这样做 因为你正在
  • HTML5 canvas 类上的 jQuery getContext

    这段代码的工作原理
  • Numpy 数组的长整数形状

    如果我构造一个像这样的 numpy 矩阵 A array 1 2 3 4 5 6 然后输入A shape我得到结果 2L 3L 为什么我得到的形状格式很长 我可以重新启动一切 但仍然遇到同样的问题 据我所知 只有当我构造数组时才会遇到这个问
  • Rails Paperclip 只能用于图像吗?

    是否有任何 Rails 库用于管理与 ActiveRecord 连接的文件附件 I know 回形针 但它似乎主要适合图像 他们确实提到了音频和 pdf 文件github项目页面 但没有进一步解释不同文件类型的用法 属性如 style如果您
  • ARM直接内存操作

    ARM中有支持直接内存操作的指令吗 所以而不是 cc cc 100 mov r3 0 ldr r1 r3 0 add r1 r1 100 str r1 r3 0 它是否有类似或接近的东西 add r3 0 100 I know this i
  • MongoEngine 指定查询的读取首选项

    我正在使用 Mongo 2 6 Pymongo 2 7 2 和 Mongoengine 0 8 7 对于特定的读取查询 我想使用副本集的辅助副本 因此 正如 mongoengine 文档中所指定的here我的查询如下 from pymong
  • JVM 如何执行 Try catch finally 块

    根据 Java 语言规范 第 14 20 2 节 带有finally 块的try 语句首先执行try 块 然后就有一个选择 If execution of the try block completes normally then the
  • 根据国家/地区获取货币符号

    我有一个显示货币的 TextView 默认情况下 我的文本视图的文本是 0 00我怎样才能做到这样 根据用户选择而变化 我有以下代码 Locale locale new Locale en US Currency currency Curr
  • 类是结构体还是结构体指针

    如果我没记错的话 结构意味着对象 结构指针意味着指向对象的指针 对吗 在一篇文章中 它说类是结构 这意味着它们是对象 Filter the list of all classes The traditional definition of
  • 从 Facebook 获取电子邮件 - FB android SDK

    我使用以下代码从 Facebook 获取用户的电子邮件和姓名 protected void onCreate Bundle savedInstanceState Display page setContentView R layout ac
  • 致命错误:sys/socket.h:32位上没有这样的文件或目录

    当使用 32 位编译我的程序时 gcc m32 program c o program 我收到以下错误致命错误 sys socket h 没有这样的文件或目录 但与 gcc program c o program 效果很好 有什么解决方法吗
  • KSoap2 和 KvmSerialized - 如何发送复杂的对象,如 Stringarrays

    我想将一个复杂的对象从我的 Ksoap 客户端发送到我的 Web 服务 它是我的类别类别的一个对象 该代码基于本教程的示例 http seesharpgears blogspot de 2010 10 ksoap android web s
  • 如何在Hive中获取数组中的前n个元素

    我使用 split 函数在 Hive 中创建一个数组 如何从数组中获取前 n 个元素 并且我想遍历子数组 代码示例 select col1 from table where split col2 0 5 0 5 看起来像 python 风格
  • 如何找到符号的完全限定名称空间?

    如果我有一个符号 其名称空间是别名 例如 q w 我如何找到它的实际名称空间 例如actual namespace w 我知道resolve会给我完全限定的 var 但我不知道如何获取 var 的命名空间 我能做的最好的事情就是 defn
  • MATLAB 中的矩阵运算

    我正在尝试简化我的代码 但遇到了一个小问题 让 v 1 2 3 a1 4 5 6 a2 7 8 9 A a1 a2 我的目标是计算 u v a1 v a2 仅使用v一度 这可能吗 是的 你可以使用bsxfun 例如 u bsxfun tim
  • `use std::io::Result as IOResult;` 比 `use std::io;` 仅仅引用 Rust 中的 `io::Result` 更高效吗?

    在学习 Rust 的过程中 我看到了人们导入库的多种方式 例如std io Result 例如 use std io Result as IOResult and pub type IOResult
  • R 中的表情符号 [UTF-8 编码]

    我正在尝试对 R 进行表情符号分析 我存储了一些带有表情符号的推文 这是我要分析的推文之一 gt tweetn2 1 Programme du week end xed xa0 xbd xed xb2 x83 xed xa0 xbc xed
  • Rails 迁移抱怨使用回形针的未定义方法“附件”

    Lemmie 在开头说我对 Rails 还很陌生 我们的应用程序使用回形针 3 2 4 来管理附件 像往常一样 我生成了一个类似于以下内容的迁移 class AddAttachmentPhotoToPhpfoxUsers lt Active
  • 是否有必要在 C# 中显式删除事件处理程序

    我有一堂课提供一些活动 该类是全局声明的 但不是在该全局声明上实例化的 它是根据需要在需要它的方法中实例化的 每次方法中需要该类时 都会对其进行实例化并注册事件处理程序 在方法超出范围之前是否有必要显式删除事件处理程序 当方法超出范围时 类