C# - 取消绑定(bind)结构 "destruction"上的事件

标签 c# events memory struct destructor

<分区>

我想编写一个脚本引擎并使用结构而不是类来存储变量的数据,以避免在创建新类实例时涉及的内存分配。

我的第一个问题是:在创建结构时是否也有内存分配,或者它是在某种堆栈上创建的(即实际堆栈或局部堆栈的预分配内存区域)?

我的第二个问题是:想象一个结构有一些方法作为事件处理程序附加到其他对象的事件上。由于没有析构函数,当结构被销毁时,如何取消绑定(bind)这些事件处理程序?我是否必须手动执行此操作,还是被迫改用类?我不想为整数等值类型数据分配内存。

最佳答案

不要为了它们所谓的效率而使用值类型。如果某些东西在设计上不应该是值类型,请不要为了获得几个 CPU 周期而将其设为值类型。

I would like to [...] use structures instead of classes [to] avoid the memory allocation(s) involved when creating a new class instance.

我认为你的意思是“动态内存分配”,因为肯定有一些内存分配给每个 struct

根据情况,可能会结合使用struct 进行动态内存分配。具体来说,当您将 struct 装箱为 object 时,就会发生这种情况。

is there also a memory allocation when creating a struct, or it is created on some kind of stack?

如果这是一个局部变量,则值类型的内存分配在堆栈上,或者如果它是另一个 struct 类中的字段,则分配在承载该值的类中

some of its methods attached as event handlers onto events of other objects. How do I unbind event handlers when the struct is destroyed since there is no destructor?

我们先不着急,首先考虑如何将 struct 的方法作为处理程序附加到其他对象的事件。当您执行附件时,您的 struct 将被装箱以捕获到事件处理程序的闭包中,这可能会造成很大的困惑。

考虑这个例子:

delegate void Foo();

struct Bar {
    public int X;
    public void DoIt() {
        X++;
        Console.WriteLine("X={0}", X);
    }
}
public static void Main() {
    Bar b = new Bar();
    var foo = new Foo(b.DoIt); // Watch out!
    foo();
    foo();
    foo();
    Console.WriteLine("X={0} What???", b.X);
}

当您调用 foo 事件处理程序时,Bar 内的 X 会按预期进行修改。但是看看当您检查 bX 的实际值时会发生什么,您从中创建了一个委托(delegate):它的值仍然为零! ( demo 1 )

一旦您将 Bar 设为类 ( demo 2 ),此行为就会改变。

这个故事的寓意是,您应该非常小心地对待值类型,尤其是在需要捕获的情况下,例如创建委托(delegate)。如果您对局部变量进行委托(delegate),您就会知道该变量的作用域在哪里结束,因此您可以正确地处理该委托(delegate):

Bar b = new Bar();
try {
    someClass.SomeEvent += b.DoIt();
} finally {
    someClass.SomeEvent -= b.DoIt();    
}

但是,如果委托(delegate)将变量的范围扩展到局部之外,则行为将出乎意料且令人困惑。

关于C# - 取消绑定(bind)结构 "destruction"上的事件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46830694/

相关文章:

c# - 如何控制 MVVM WinRT/XAML Windows Store 应用程序中 ListView 的滚动位置?

c++ - 立即作为参数传递的对象的生命周期是多少?

c - 如何在 Linux 中限制 C 代码的堆大小

c++ - 什么是 “undetectable means”,它们如何更改C/C++程序的对象?

c# - Akka.net/Generics and Database & Entity Framework

c# - 大对象堆中的大字符串会导致问题——但在任何情况下它都必须以字符串结束

c# - 另一个类中的 WPF 事件处理程序

javascript - ionic 形式的键盘事件

java - 我们可以使用EventObject在不同的JVM之间进行通信吗?

c# - Web 服务中的返回类对象更改了其命名空间