我是.net的新手。我对C#中的析构函数机制感到困惑。请澄清
在C#中,析构函数由CLR转换为finalize方法。 如果我们尝试覆盖它(不使用析构函数),将会出错 错误2不要覆盖object.Finalize。相反,提供一个析构函数。
但似乎mscorlib.dll中的Object calss实现已将finalize定义为protected override void Finalize(){},那么为什么我们无法覆盖它,那是什么虚函数。
为什么设计是这样的,它是否与c ++析构函数概念一致。
当我们转到对象类的定义时,没有提到finalize方法,那么hmscorlib.dll定义如何显示finalize函数。 这是否意味着将默认析构函数转换为finalize方法。
public class Object
{
public Object();
public virtual bool Equals(object obj);
public static bool Equals(object objA, object objB);
public virtual int GetHashCode();
public Type GetType();
protected object MemberwiseClone();
public static bool ReferenceEquals(object objA, object objB);
public virtual string ToString();
}
答案 0 :(得分:20)
我是.NET的新手,我对C#中的析构函数机制感到困惑。请澄清。
不确定。我同意这令人困惑。
在C#中,析构函数由CLR转换为finalize方法。
正确。好吧,我会说这是由C#编译器完成的,而不是CLR,但我理解你的意思。
如果我们尝试覆盖它(不使用析构函数),则会收到错误“不要覆盖object.Finalize。而是提供析构函数。”
正确。
似乎mscorlib.dll中的Object类实现已将finalize定义为protected override void Finalize(){}
正确。
那么为什么我们不能覆盖呢?这就是虚拟功能的用途。
因为那时会有两种方式来编写析构函数。那会令人困惑。我们希望只有一种方法来编写析构函数。
为什么这样的设计?是否与c ++析构函数概念一致?
这是一个原因,是的。还有其他原因。以下是一些:
通过逻辑分离“析构函数”和“覆盖终结方法”的概念,我们可以通过其他环境中的其他机制实现析构函数。这还没有发生,但是未来我们可能会编写一个C#版本,比如用于在具有与标准CLR语义不同的垃圾收集器语义的环境中构建设备驱动程序。在该环境中,析构函数的语义可能更像是C ++析构函数的语义,而不像GC终结器。
终结者是非常特殊的方法。你不能像常规方法那样称呼它们;只有垃圾收集器可以调用它们。他们有不同的异常处理规则。它们必须确保在派生类终结器之后严格调用基类终结器。它们非常特殊,将它们暴露为任何其他方法似乎很危险。如果你有一种方法只是坐在那里你可以打电话,你可以把任何你想要的东西,等等,这使得很容易忘记终结者的特殊性。使用特殊语法强调这是特殊代码。
另外,当我们转到对象类的定义时,没有提到finalize方法,那么mscorlib.dll定义如何显示finalize函数。
假设我们在对象浏览器中显示了一个名为MagicUnicorn的方法,如果您尝试调用它或覆盖它,则会收到错误消息“不要这样做!”。如果你不能做任何事情,为什么还要费心去展示MagicUnicorn方法呢?那只是无益的噪音。
现在,如果您反汇编mscorlib,那么当然确实存在特殊的Finalize方法。
是否意味着将默认析构函数转换为finalize方法。
是
答案 1 :(得分:4)
'为什么会这样?' 通过设计决定。可能与C ++相匹配,但它确实无关紧要。
hmscorlib.dll如何定义 显示最终化函数
C#编译器可能有一个特殊的干预。同样,它没有实际的区别。
如果你真的需要一个终结器,那就写一个析构函数。更重要的是:你几乎不需要。
要了解这个选择是多么随意:在VB中你可以override Finalize。这两种语言可以非常愉快地使用(并继承)其他类型的语言。
答案 2 :(得分:0)
要覆盖Finalize()
,您必须使用终结器语法。 CLI在内部对某些事物使用固定名称,例如名为.ctor
的所有实例构造函数,以及名为.cctor
的所有静态构造函数。当C#编译器编写输出程序集时,它确保为它发出的项使用正确的名称,其中包括将析构函数编写为名称为Finalize()
而不是~T()
。其他.NET语言的编译器也必须遵循这些相同的规则来处理它们自己的语义。
class A
{
~A() { /* ... */ }
}
关于终结者的时间和方式,请在此处查找有关终结者和IDisposable
的许多其他问题。
答案 3 :(得分:0)
是否意味着将默认析构函数转换为finalize方法
是的,C#中的默认(且唯一)析构函数语法被编译为Finalize
方法。这很可能为C ++开发人员提供熟悉的语法。有关详细信息,请参阅Destructors on MSDN。
答案 4 :(得分:0)
在C ++中,您需要析构函数是虚拟的。原因是,这就是它被调用的方式
A a = new B() //where B derived from A
delete a;
C ++上有点生疏,如果我错了,请原谅我。但是请注意,删除传递的引用可能是基类。
在C#中,您不会调用终结器。它由垃圾收集器在内部调用。垃圾收集器没有理由对之前分配的引用类型感兴趣,并直接获取对象:)
现在,终结器只是从C ++中获取语法。因此混乱。
其他人说的是,您通常不需要最终确定。这就是原因。
如果实现IDisposable,您可以获取“using”语句的帮助来决定变量的范围并在需要时进行处理。使用Finalization时,GC将决定何时调用该方法。这意味着,如果您需要释放资源,时机可能是错误的。
希望这会有所帮助。