2010-04-06 102 views
5

我是新来的.NET ..和我很困惑,在C#析构函数机制..please澄清为什么Finalize方法不能覆盖

在C#中的析构函数转换由CLR敲定方法。 如果我们尝试覆盖它(不使用析构函数),将会出错 错误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

要覆盖Finalize(),必须使用终结器语法。 CLI在内部对某些内容使用固定名称,如全部为的实例构造函数名为.ctor,以及所有名为.cctor的静态构造函数。当C#编译器写入输出程序集时,它确保为其发出的项目使用正确的名称,其中包括将析构函数的名称写为Finalize()而不是~T()。其他.NET语言的编译器也必须遵循这些相同的规则来进行自己的语义。

class A 
{ 
    ~A() { /* ... */ } 
} 

对于何时终结的怎么样,找这里的许多其他问题与终结和IDisposable处理。

+1

我认为他们明白,并且正在寻求解释_why_。 – 2010-04-06 17:48:59

4

'为什么这样?'
由设计决定。可能与C++匹配,但它确实无关紧要。

怎样的hmscorlib.dll定义 显示的finalize函数

有可能是在C#编译器的特别干预。再次,它没有实际的区别。

如果你真的需要一个终结器,写一个析构函数。更重要的是:你几乎从不需要。

要看看这个选择有多么随意:在VB中你可以override Finalize。而这两种语言可以非常高兴地使用(并继承)其他类型。

+3

+1“你几乎从不需要”。通常需要'IDisposable'接口。 – 2010-04-06 17:53:54

+0

@Richard,是的,IDisposable类经常但不总是有析构函数。没有IDisposable的析构函数非常罕见(甚至怀疑)。 – 2010-04-06 17:58:13

0

这是否意味着默认的析构函数转化为最终确定方法

是,默认的(唯一的)析构函数语法C#编译为Finalize方法。这很可能为C++开发人员提供了一种熟悉的语法。有关更多信息,请参阅Destructors on MSDN

+1

C#中没有默认的析构函数。 – 2010-04-06 18:00:37

0

在C++中,你需要析构函数为虚拟的。究其原因,这是它是如何在调用C++

A a = new B() //where B derived from A 
delete a; 

有点生疏了,所以请原谅我,如果我错了。但是请看,删除被传递了一个可能是基类的引用。

在C#中,您不会调用终结器。它由垃圾收集器在内部调用。没有理由垃圾收集器会对之前分配的参考类型感兴趣,并直接获取对象:)

现在,终结器只是从C++获取语法。因此混乱。

其他人在说什么是,你通常不需要最终确定。这就是为什么。

如果您实现了IDisposable,那么可以借助“using”语句来决定变量的范围并在需要时进行处置。通过Finalization,GC决定何时调用该方法。这意味着,如果您需要释放资源,时间可能是错误的。

希望这会有所帮助。

20

刚刚接触.NET,我对C#中的析构函数机制感到困惑。请澄清。

当然。我同意这令人困惑。

在C#析构函数被转换由CLR敲定方法。

正确。那么,我会说这是由C#编译器完成的,而不是CLR,但我理解你的意思。

如果我们尝试覆盖它(不使用析构函数),将会得到一个错误“不要覆盖object.Finalize,而是提供一个析构函数。”

正确。

似乎在mscorlib.dll Object类实现已敲定定义为保护覆盖无效的Finalize(){}

正确的。

那么为什么我们不能重写呢?这是一个虚拟功能。

因为接下来会有两个的方法来编写析构函数。这会让人困惑。我们希望只有一种方法来编写析构函数。

为什么这样的设计?它是否与C++析构函数概念一致?

这是一个原因,是的。还有其他原因。这里有几个:

  • 通过逻辑分离的“析构函数”的概念和“覆盖finalize方法,”我们有可能通过在其他环境中其他一些机制实现析构函数。这种情况还没有发生,但可能发生的事情是,将来我们会编写一个C#版本,例如,用于在具有与标准CLR语义不同的垃圾收集器语义的环境中构建设备驱动程序。在那个环境中,析构函数的语义可能更像C++析构函数的语义,而不像GC终结器。

  • 终结者是非常非常特殊的方法。你不能像常规方法那样称呼他们;只有垃圾收集器可以调用它们。他们有不同的异常处理规则。他们必须确保在派生类终结器之后严格调用基类终结器。它们非常特殊,将它们暴露为任何其他方法似乎是危险的。如果你有一种方法就是坐在那里,你可以打电话,你可以放入任何你想要的东西,等等,这很容易忘记终结者有多特别。有一个特殊的语法强调这是特殊的代码。

而且当我们去的对象类的定义,有finalize方法中没有提及,那么请问在mscorlib.dll中定义显示的finalize函数。

假设我们在名为MagicUnicorn的对象浏览器中显示了一个方法,并且如果您试图调用它或覆盖它,您会看到一个错误,说“不要那样做!”。如果你不能用它做任何事情,为什么还要展示MagicUnicorn方法?这只是无益的噪音。

现在,如果你反汇编mscorlib,那当然真的有特殊的Finalize方法。

是否意味着默认析构函数转换为finalize方法。

是的。

+0

有没有什么办法可以在不使用'GC.SuppressFinalize()'和'GC.KeepAlive()'的名称有效硬编码的情况下正确使用析构函数*?如果C#在需要时提供了调用此类函数的语法(无需使用特定于框架的名称),我可能会在析构函数语法中看到一些值。另一方面,如果编写一个适当的自清洁对象需要至少使用两个特定于框架的'GC。*'方法,我不确定这个难题的一小部分是特定于语言的特定值而不是特定于框架。我错过了什么吗? – supercat 2012-06-18 23:22:18

相关问题