如何检测c#中的虚方法是否被重写

发布于 2024-12-01 20:44:20 字数 445 浏览 2 评论 0原文

是否可以确定虚拟方法是否已被重写:

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() 因为它不执行任何操作)。我向你保证我有一个合法的理由。有什么想法吗?

Is it possible to determine if a virtual method has been overridden:

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();
  }
}

I realize that this example seems stupid (e.g. why don't you just call DoSomethingExtra() since it doesn't do anything). I assure you I have a legitimate case for this. Any ideas?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

绝對不後悔。 2024-12-08 20:44:20

因此,在 C# 中,可以声明虚拟方法而不实现它。

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

上面的代码报告错误Error 1 'ABase.DoSomethingExtra(object)'必须声明一个主体,因为它没有标记为抽象、外部或部分

处理此问题的典型方法是仅声明具有空操作实现的方法,并调用它:

class ABase {
  public void DoSomething(object p)
  {
    p.Process();
    DoSomethingExtra(p); // Always call
  }
  public virtual void DoSomethingExtra(object p)
  {
      // Do nothing here
  }
}

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

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

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

话虽这么说,我强烈质疑这里的设计目标。您的问题基本上是在询问一种违反里氏替换原则的具体方法,该原则是面向对象编程的核心原则。这将会降低你的代码的性能和可维护性......

So in C# it is possible to declare a virtual method without implementing it.

This is not possible. You can declare a method as abstract, but if the method is virtual, it will have some implementation (even if the implementation is effectively a null op).

Your code above reports the error Error 1 'ABase.DoSomethingExtra(object)' must declare a body because it is not marked abstract, extern, or partial.

The typical way to handle this is to just declare the method with a null op implementation, and call it:

class ABase {
  public void DoSomething(object p)
  {
    p.Process();
    DoSomethingExtra(p); // Always call
  }
  public virtual void DoSomethingExtra(object p)
  {
      // Do nothing here
  }
}

Edit: Now that your question has been edited, I'll give you more information related to your edit, in particular, this:

I realize that this example seems stupid (e.g. why don't you just call DoSomethingExtra() since it doesn't do anything). I assure you I have a legitimate case for this. Any ideas?

There is no direct way to determine whether the current instance has overriden your virtual method. This would likely require some pretty nasty, unmaintainable code, such as checking the method body declaring type via reflection to see what is there.

That being said, I would strongly question the design goal here. Your question is basically asking for a specific way to violate the Liskov Substitution Principle, which is one of the core principles in object oriented programming. This is going to have the effect of making your code less performant and much less maintainable...

或十年 2024-12-08 20:44:20

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

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

Reflection is a good answer to this question.

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);

I hope that you will find this usefull.

Once I were implementing a special object viewer, when the object was unknown I would use ToString() unless it was not overridden.

听风念你 2024-12-08 20:44:20

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

反射是在运行时执行此操作的唯一方法。这应该带有健康警告,但是从面向对象编程的角度来看,它应该被视为非常糟糕的想法™。基类通常不应该知道或关心派生类是如何实现的。

Check this out: Detect if a method was overridden using Reflection (C#)

Reflection would be the only way to do this at runtime. This should come with a health warning however, it should be considered a Very Bad Idea™ from an OOP perspective. A base class should not generally know or care how a derived class is implemented.

夏末的微笑 2024-12-08 20:44:20

有几种选择:

如果派生类必须实现DoSomethingExtra(),则将方法和类声明为抽象。这将迫使具体的派生类有一个实现。然后,您可以从基类代码中调用 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; } }
}

不过,此解决方案有点脆弱,因为派生类可能会忘记在以下情况下重写该属性:覆盖该方法。我认为不做任何事情的基础实现是最简单的方法。

There are a few options:

If derived classes must implement DoSomethingExtra(), then declare the method and the class as abstract. That will force a concrete derived class to have an implementation. You can then just call DoSomethingExtra() from base class code, knowing an implementation will exist.

abstract class ABase {

  public void DoSomething(object p)
  {
    p.Process();
    DoSomethingExtra(p);
  }

  public abstract void DoSomethingExtra(object p);
}

If derived class may implement the method, then just include a default implementation in the base class, which will be called if no derived implementation is available.

Another option is to have a flag that derived classes can set, indicating if they want something extra to be done:

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; } }
}

This solution is a little brittle, though, since a derived class could forget to override the property when overriding the method. I think having a do-nothing base implementation is the easiest way to go.

ま昔日黯然 2024-12-08 20:44:20

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

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

更新:提供的链接这里比必要的更详细,但也不完整。上面的版本也适用于受保护的方法和虚拟属性(这就是为什么您使用 GetMember 而不是限制性更强的 GetMethod),这两个链接都没有解决。

This is the simplest way to get what you want:

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

Update: The link provided here is more verbose than necessary, but is also incomplete. The version above will also work for protected methods and virtual properties (That's why you use GetMember instead of the more restrictive GetMethod), neither of which the link addresses.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文