关于c#:为什么结构不能有析构函数?

Why structs cannot have destructors?

对于你认为的这个问题,面试的最佳答案是什么?

我想我在这里没有找到这个的副本,如果有,请链接它。


另一种看待这一点的方法——而不仅仅是引用说明结构不能/不具有析构函数的规范——考虑如果规范被更改,那么会发生什么——或者更确切地说,让我们问一个问题:我们能猜出为什么语言设计者决定不允许结构首先具有"析构函数"?

(这里不要挂断"析构函数"这个词;我们主要讨论的是一个神奇的结构方法,当变量超出范围时,它会自动被调用。换句话说,类似C++的析构函数的语言特征。

首先要意识到的是,我们不在乎释放记忆。无论对象是在堆栈上还是在堆上(例如,类中的结构),内存迟早都会以某种方式处理;要么从堆栈中弹出,要么收集。最初拥有类似于析构函数的东西的真正原因是为了管理外部资源——比如文件句柄、窗口句柄,或者其他需要特殊处理才能清除它们的东西,而clr本身并不知道。

现在假设您允许一个结构有一个析构函数来完成这个清理。好的。直到您认识到当结构作为参数传递时,它们都是通过值传递的:它们是被复制的。现在有两个具有相同内部字段的结构,它们都将尝试清理同一对象。一个会先发生,所以使用另一个的代码随后会开始神秘地失败…然后它自己的清理就会失败(希望!-最糟糕的情况是,它可能会成功地清除其他一些随机资源——例如,在重用句柄值的情况下,这种情况可能会发生。)

可以想象,对于作为参数的结构,您可以做一个特殊的例子,这样它们的"析构函数"就不会运行(但要小心-现在需要记住,当调用函数时,它始终是外部的"拥有"实际资源-因此,现在一些结构与其他结构有细微的不同…)-但是您仍然对regul有这个问题。结构变量,其中一个可以分配给另一个,生成一个副本。

你也许可以通过添加一个特殊的机制来完成分配操作,这使得新的结构可以用新的副本来协商底层资源的所有权——也许他们共享它,或者将所有权从旧的转移到新的-但是现在你已经基本上进入了C++的土地,在那里你需要拷贝CO。nstructor、赋值操作符和添加了一系列微妙的内容,等待捕获不知情的新手程序员。并且记住C语言的整个点是尽可能避免这种类型的C++复杂度。

而且,正如另一个答案所指出的那样,为了让事情变得更加混乱,结构不仅仅作为局部对象存在。对于局部变量,范围是好的并且定义得很好;但是结构也可以是类对象的成员。在这种情况下,何时应该调用"析构函数"?当然,您可以在容器类完成时执行此操作;但是现在您有了一种机制,根据结构所在的位置,它的行为会非常不同:如果结构是本地的,则在作用域结束时立即触发;如果结构在类中,则会延迟触发…因此,如果您真的关心确保某个结构中的某个资源在某个特定的时间被清理掉,并且如果您的结构最终可能成为类的成员,那么您可能需要像IDisposable/Using()这样的明确的东西来确保您的基础被覆盖。

因此,虽然我不能声称我是语言设计师,但我可以很好地猜测,他们决定不包括这样一个功能的原因之一是,这将是一个蠕虫罐头,他们希望保持C相当简单。


来自乔恩·贾格尔:

"结构不能有析构函数。析构函数只是伪装为object.Finalize的重写,而作为值类型的结构不受垃圾收集的影响。"


除数组和字符串之外的每个对象都以相同的方式存储在堆中:一个头,它提供有关"与对象相关"属性(其类型、是否由任何活动的监视器锁使用、是否具有非抑制的Finalize方法等)及其数据(即所有类型的实例字段(public、public、public)的信息。private和protected混合使用,基类字段出现在派生类型字段之前)。因为每个堆对象都有一个头,所以系统可以引用任何对象,并知道它是什么,以及垃圾收集器应该如何处理它。如果系统有一个已经创建的所有对象的列表,并且有一个Finalize方法,那么它可以检查列表中的每个对象,看看它的Finalize方法是否未被批准,并对其进行适当的操作。

结构存储时不带任何头;像Point这样有两个整型字段的结构只存储为两个整型。虽然可以将ref传递给结构(当结构作为ref参数传递时,就会创建这样的东西),但是使用ref的代码必须知道ref指向的是哪种类型的结构,因为ref和结构本身都不包含该信息。此外,堆对象只能由垃圾收集器创建,这将确保创建的任何对象在下一个GC周期之前始终存在。相比之下,用户代码可以自己创建和销毁结构(通常在堆栈上);如果代码创建了一个结构和一个ref,并将该结构传递给一个被调用的例程,那么在被调用的例程返回之前,代码无法销毁该结构(或做任何事情),因此该结构是有保证的至少在被调用的例程退出之前存在。另一方面,一旦被调用的例程退出,那么给定的ref应该被假定为无效,因为调用方可以在此后的任何时间任意销毁该结构。


因为根据定义,析构函数用于析构函数类的实例,而结构是值类型。

参考:http://msdn.microsoft.com/en-us/library/66x5fx1b.aspx

用微软自己的话来说:"Destructors are used to destruct instances of classes.",所以问"为什么你不能在(不是类的东西)上使用析构函数?"有点傻。^ ^