抽象类的析构函数

The*_*kai 4 c# syntax inheritance virtual-destructor

在C++中我知道当一个打算从基类继承时,通常应该使用虚拟析构函数.但是,使用C#我不知道该怎么做.请考虑以下代码:

public abstract class Character
{
    private string characterName;
    public int health;

    Character()
    {

    }

    ~Character(){

    }

    public virtual void SetCharacterName( string tempName )
    {
        characterName = tempName;
    }

    public virtual string GetCharacterName( )
    {
        return characterName;
    }
}
Run Code Online (Sandbox Code Playgroud)

(注意:我听说Unity的Unity3Ds实现与标准略有不同.也许忽略一些小的格式错误,代码似乎功能......)

我的第一直觉是将~Character()析构函数设为虚拟,将其定义为:

virtual ~Character(){

}
Run Code Online (Sandbox Code Playgroud)

但这样做会导致IDE返回错误.

在C#中,对于希望继承的抽象类,使用虚拟析构函数是必要的还是被认为是标准的?还是有其他方法用C#制作虚拟析构函数?

Nic*_*rey 9

C#没有确定性破坏.事实上,它本身并没有真正的析构函数:它有终结器和IDisposable.

如果垃圾收集对象实例,垃圾邮件将清理垃圾.当应用程序域终止时,所有对象将[最终]以这种或那种方式被清除,但是给定对象可能在应用程序域的持续时间内闲置.在您的情况下,您不需要做任何事情,因为您的对象没有需要清理的资源.当GC扫描时,未引用的对象将被正确处理掉.

大多数情况下,人们不需要终结者.您可能想在http://msdn.microsoft.com/en-us/library/system.object.finalize.aspx上阅读Finalizer,并注意

终结器执行的确切时间未定义.要确保为类的实例确定性地释放资源,请实现Close方法或提供IDisposable.Dispose实现.

您可能还想阅读了解何时在.NET类中使用Finalizer并注意:

为什么Finalize方法不好?

...

如果一个对象有一个终结器,它将被放置在FinalizationQueue中并受到一些额外的清理.一旦在线程或全局引用上不再引用该对象,下次垃圾收集器(GC)运行时,它将看到该对象已准备好被收集.但它还无法收集它.它必须让Finalizer先运行.因此GC将完成收集,然后Finalizer将完成对象,然后将发生另一个GC收集.

这会对性能产生巨大影响,因为您应该记住,所有托管线程都将在GC上停止等待,然后GC将停止等待Finalizer线程.

有很多关于Finalization的数据,所以我鼓励你尽可能多地阅读它,以便你以最好的方式使用它.

如果您的对象需要确定性的东西,您可以实现IDisposable并显式调用Dispose()或使用using块:

using ( Character foo = CharacterFactory.CreateInstance("Jane") )
{
   // do something useful with Jane
}
Run Code Online (Sandbox Code Playgroud)

using退出封闭块时,foo.Dispose()保证被调用.它与此代码相同(除了范围foo):

Character foo = ... ;
try
{
  ...
}
finally
{
  foo.Dispose() ;
}
Run Code Online (Sandbox Code Playgroud)

但是,重点IDisposable更多的是确保及时释放非托管资源.当您的对象超出范围并且正在等待GC进行操作时,如果您阻止了400个用户,则DBA往往会变得脾气暴躁,从而使正在运行的查询保持运行状态.或者您的对象超出范围,打开一个独占锁定的文件.


Chr*_*heD 7

在C#中,对于希望继承的抽象类,使用虚拟析构函数是必要的还是被认为是标准的?

通常,您不会在C#中使用任何析构函数.那些可能会或可能不会被垃圾收集器随时调用(或不调用).

当您需要确定性清理时,请实现IDisposable接口,并使用using进行清理(例如,非托管资源).

析构函数不能被继承或重载.相关的stackoverflow线程有更多细节:C#中的继承和析构函数