在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;
}
}
(注意:我听说过C#的Unity3Ds实现与标准略有不同。也许忽略了一些小的格式错误,代码似乎功能正常......)
我的第一直觉是将~Character()析构函数设为虚拟,将其定义为:
virtual ~Character(){
}
但这样做会导致IDE返回错误。
在C#中,对于希望继承的抽象类,使用虚拟析构函数是必要的还是被认为是标准的?或者是否有其他方法可以使用C#制作虚拟析构函数?
答案 0 :(得分:9)
C#没有确定性破坏。事实上,它本身并没有真正的析构函数:它有终结函数和IDisposable
。
GC会在垃圾收集对象实例时进行清理。当应用程序域终止时,所有对象[最终]会以这种或那种方式被清除,但是在给定域的持续时间内,给定对象可能会挂起。在您的情况下,您不需要做任何事情,因为您的对象没有需要清理的资源。当GC扫描时,未引用的对象将被妥善处理。
大多数情况下,人们不需要终结者。您可能希望在http://msdn.microsoft.com/en-us/library/system.object.finalize.aspx阅读终结者并注意
终结器执行的确切时间未定义。确保确定性释放 您的类实例的资源,实现Close方法或提供 IDisposable.Dispose implementation。
您可能还想阅读Understanding when to use a Finalizer in your .NET class并注意:
为什么Finalize方法不好?
...
如果某个对象有一个终结器,它将被放置在FinalizationQueue中并且是主题 所以一些额外的清理。一旦线程上不再引用该对象或 从全局引用开始,下次垃圾收集器(GC)运行时,它会看到这一点 对象已准备好收集。但它还无法收集它。它必须让 终结者首先运行。因此GC将完成收集,然后Finalizer将完成 该对象,然后将发生另一个GC集合。
这会对性能产生巨大影响,因为您应该记住所有管理 线程将停止等待GC,然后GC将停止等待 终结者线程。
有很多关于Finalization的数据,所以我鼓励你阅读它 尽可能地以最佳方式使用它。
如果您的对象需要具有确定性的内容,则可以实现IDisposable
并明确调用Dispose()
或使用using
块:
using ( Character foo = CharacterFactory.CreateInstance("Jane") )
{
// do something useful with Jane
}
当退出封闭的using
块时,保证调用foo.Dispose()
。它与此代码相同(foo
的范围除外):
Character foo = ... ;
try
{
...
}
finally
{
foo.Dispose() ;
}
但是,IDisposable
更重要的是确保及时发布非托管资源。当您的对象超出范围并且正在等待GC离开时,DBA往往会在阻止400个用户时变得脾气暴躁,从而使正在运行的查询保持运行状态。或者您的对象超出范围,保留一个独占锁定的文件。
答案 1 :(得分:7)
在C#中,对于希望继承的抽象类使用虚拟析构函数是必要的还是被认为是标准的?
通常,您不会在C#中使用任何析构函数。那些垃圾收集器可能会或可能不会在任何时候(或不是)调用它们。
当您需要确定性清理时,请实施IDisposable接口,并使用using
块to clean up(例如,非托管资源)。
析构函数cannot be inherited or overloaded。相关的stackoverflow线程包含更多详细信息:Inheritance and Destructors in C#