是否可以确定是否已覆盖虚拟方法:
class ABase {
public void DoSomething(object p)
{
p.Process();
if( /* DoSomethingExtra is implemented */ )
DoSomethingExtra(p);
}
public virtual void DoSomethingExtra(object p) { }
}
class ADerived {
public override void DoSomethingExtra(object p)
{
p.ProcessMore();
}
}
我意识到这个例子看起来很愚蠢(例如,你为什么不调用DoSomethingExtra(),因为它没有做任何事情)。我向你保证,我有一个合法的案例。有什么想法吗?
答案 0 :(得分:10)
因此,在C#中,可以在不实现的情况下声明虚方法。
这是不可能的。您可以将方法声明为 abstract ,但如果该方法是虚拟的,则它将具有一些实现(即使实现实际上是null操作)。
上面的代码报告错误Error 1 'ABase.DoSomethingExtra(object)' must declare a body because it is not marked abstract, extern, or partial
。
处理此问题的典型方法是使用null op实现声明方法,并调用它:
class ABase {
public void DoSomething(object p)
{
p.Process();
DoSomethingExtra(p); // Always call
}
public virtual void DoSomethingExtra(object p)
{
// Do nothing here
}
}
编辑:既然您的问题已经过编辑,我会为您提供与您的编辑相关的更多信息,特别是:
我意识到这个例子看起来很愚蠢(例如,你为什么不调用DoSomethingExtra(),因为它没有做任何事情)。我向你保证,我有一个合法的案例。有什么想法吗?
没有直接的方法来确定当前实例是否覆盖了您的虚方法。这可能需要一些非常讨厌,不可维护的代码,例如检查method body declaring type via reflection以查看其中的内容。
话虽如此,我强烈质疑这里的设计目标。你的问题基本上是要求一种违反Liskov Substitution Principle的特定方式,这是面向对象编程的核心原则之一。这将导致您的代码性能降低,维护性降低......
答案 1 :(得分:5)
反思是这个问题的一个很好的答案。
using System.Reflection;
Type classType = typeof(ADerived);
MethodInfo method = classType.GetMethod("DoSomethingExtra");
if (method.DeclaringType == typeof(ABase))
Console.WriteLine("DoSomethingExtra not overridden.");
else
Console.WriteLine("DoSomethingExtra is overridden by " + method.DeclaringType.Name);
我希望你会发现这很有用。
一旦我实现了一个特殊的对象查看器,当对象未知时,我将使用ToString(),除非它没有被覆盖。
答案 2 :(得分:2)
有几个选择:
如果派生类必须实现DoSomethingExtra()
,则将方法和类声明为abstract
。这将迫使具体派生类具有实现。然后,您可以从基类代码中调用DoSomethingExtra()
,知道实现将存在。
abstract class ABase {
public void DoSomething(object p)
{
p.Process();
DoSomethingExtra(p);
}
public abstract void DoSomethingExtra(object p);
}
如果派生类可能实现该方法,那么只需在基类中包含一个默认实现,如果没有派生实现可用,则会调用该实现。
另一个选择是有一个派生类可以设置的标志,指示他们想要要做的额外事情:
class ABase {
public virtual bool ShouldDoSomethingExtra { get { return false; } }
public void DoSomething(object p)
{
p.Process();
if(ShouldDoSomethingExtra)
DoSomethingExtra(p);
}
public virtual void DoSomethingExtra(object p) { // Empty in base }
}
class ADerived {
public override void DoSomethingExtra(object p)
{
p.ProcessMore();
}
public override bool ShouldDoSomethingExtra { get { return true; } }
}
但是,这个解决方案有点脆弱,因为派生类在重写方法时可能会忘记覆盖属性。我认为有一个无操作的基础实现是最简单的方法。
答案 3 :(得分:2)
查看Detect if a method was overridden using Reflection (C#)
反射是在运行时执行此操作的唯一方法。这应该带有健康警告但是,从OOP的角度来看,它应该被认为是一个非常糟糕的想法(tm)。基类通常不应该知道或关心如何实现派生类。
答案 4 :(得分:1)
这是获得所需内容的最简单方法:
var isDerived = typeof(ADerived).GetMember("DoSomethingExtra",
BindingFlags.NonPublic
| BindingFlags.Instance
| BindingFlags.DeclaredOnly).Length == 0;
更新:提供的链接here比必要的更详细,但也不完整。上面的版本也适用于受保护的方法和虚拟属性(这就是您使用GetMember
而不是限制性更强的GetMethod
)的原因,这两者都不是链接地址。