如何检测是否在c#中重写了虚方法

是否可以确定是否已覆盖虚拟方法:

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(),因为它没有做任何事情)。 我向你保证,我有一个合法的案例。 有任何想法吗?

检查一下使用Reflection(C#)检测方法是否被覆盖

reflection将是在运行时执行此操作的唯一方法。 这应该带有健康警告,但是,从OOP的角度来看,它应该被认为是一个非常糟糕的想法(tm)。 基类通常不应该知道或关心如何实现派生类。

所以在C#中可以声明一个虚方法而不实现它。

这是不可能的。 您可以将方法声明为抽象 ,但如果该方法是虚拟的,则它将具有一些实现(即使实现实际上是空操作)。

上面的代码报告错误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(),因为它没有做任何事情)。 我向你保证,我有一个合法的案例。 有任何想法吗?

没有直接的方法来确定当前实例是否覆盖了您的虚方法。 这可能需要一些非常讨厌,不可维护的代码,例如通过reflection检查方法体声明类型 ,看看有什么。

话虽如此,我强烈质疑这里的设计目标。 你的问题基本上是要求一种违反Liskov替换原则的特定方式,这是面向对象编程的核心原则之一。 这将导致您的代码性能降低,维护性降低……

反思是这个问题的一个很好的答案。

 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(),除非它没有被覆盖。

有几个选择:

如果派生类必须实现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; } } } 

但是,这个解决方案有点脆弱,因为派生类在重写方法时可能会忘记覆盖属性。 我认为有一个无所事事的基础实现是最简单的方法。

这是获得所需内容的最简单方法:

 var isDerived = typeof(ADerived).GetMember("DoSomethingExtra", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly).Length == 0; 

更新: 此处提供的链接比必要的更详细,但也不完整。 上面的版本也适用于受保护的方法和虚拟属性(这就是为什么你使用GetMember而不是更严格的GetMethod ),链接地址都不是。