尽管 C# 和 .net 允许派生类重新实现接口方法,但通常最好让基类使用虚拟方法来实现接口,并让派生类覆盖该方法,在派生类可能出现的任何情况下希望增加而不是完全替换基类实现。在像 vb.net 这样的一些语言中,这可以直接完成,而不管类是否公开了与正在实现的接口成员具有相同名称和签名的公共成员。在 C# 等其他语言中,实现接口的公共方法可以标记为未密封和虚拟(允许派生类覆盖它并进行覆盖调用base.Member(params)
,但显式接口实现不能。在这些语言中,最好的方法是像:
类 MyClass : MyInterface
{
void MyInterface.DoSomething(int param)
{
做某事(参数);
}
受保护的虚拟 void doSomething(int param)
{
...
}
}
类 MyClass2 : MyClass
{
受保护的覆盖无效doSomething(int param)
{
...
base.doSomething(参数);
...
}
}
在某些情况下,让接口实现包装虚拟调用可能是有利的,因为它允许基类确保某些事情发生在被覆盖的函数之前或之后。例如,Dispose 的非虚拟接口实现可以包装虚拟 Dispose 方法:
int DisposingFlag; // System.Boolean 不适用于 Interlocked.Exchange
无效 IDisposable.Dispose()
{
if (Threading.Interlocked.CompareExchange(DisposingFlag, 1, 0) == 0)
{
处置(真);
处置标志 = 2;
Threading.Thread.MemoryBarrier();
GC.SuppressFinalize(this);
}
}
public bool Disposed { get {return (DisposingFlag != 0);} }
public boolfullyDisposed { get {return (DisposingFlag > 1);} }
这将(与 Microsoft 的默认包装器不同)确保Dispose
只被调用一次,即使多个线程尝试同时调用它。此外,它使Disposed
属性可用。使用微软的包装器,每个需要标志的派生类Disposed
都必须定义自己的;即使基类Disposed
标志是受保护的或公共的,使用它也不安全,因为直到派生类已经开始清理之后才会设置它。包装内的设置DisposingFlag
避免了这个问题。