如何检测c#中是否覆盖了虚方法

Tre*_*vor 12 c# virtual-functions

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

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();
  }
}
Run Code Online (Sandbox Code Playgroud)

我意识到这个例子看起来很愚蠢(例如,你为什么不调用DoSomethingExtra(),因为它没有做任何事情).我向你保证,我有一个合法的案例.有任何想法吗?

Ree*_*sey 10

所以在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
  }
}
Run Code Online (Sandbox Code Playgroud)

编辑:既然您的问题已被编辑,我会为您提供与您的编辑相关的更多信息,特别是:

我意识到这个例子看起来很愚蠢(例如,你为什么不调用DoSomethingExtra(),因为它没有做任何事情).我向你保证,我有一个合法的案例.有任何想法吗?

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

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

  • "你的问题基本上是要求一种特定的方式来违反Liskov替换原则."不是真的.ADerived仍然完全可以替代ABase.根据James Gaunt的评论,有一种非常干净的方法可以使用反射来确定虚拟方法的实现来自哪个类. (2认同)

Cas*_*rah 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);
Run Code Online (Sandbox Code Playgroud)

我希望您会发现这个有用。

一旦实现了特殊的对象查看器,当对象未知时,除非没有被覆盖,否则我将使用ToString()。


Jam*_*unt 3

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

\n\n

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

\n