如何检测c#中的虚方法是否被覆盖
本文关键字:方法 是否 覆盖 何检测 检测 | 更新日期: 2023-09-27 18:07:10
是否可以确定虚拟方法是否已被覆盖:
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(),因为它什么都不做)。我向你保证我有正当理由这么做。什么好主意吗?
所以在c#中可以声明一个虚方法而不实现它。
这不可能。您可以将方法声明为抽象,但如果该方法是虚拟的,则它将具有一些实现(即使该实现实际上是null op)。
上面的代码报告错误Error 1 'ABase.DoSomethingExtra(object)' must declare a body because it is not marked abstract, extern, or partial
。
class ABase {
public void DoSomething(object p)
{
p.Process();
DoSomethingExtra(p); // Always call
}
public virtual void DoSomethingExtra(object p)
{
// Do nothing here
}
}
编辑:既然你的问题已经编辑好了,我会给你更多关于你的编辑的信息,特别是,这个:
我意识到这个例子看起来很愚蠢(例如,为什么你不直接调用DoSomethingExtra(),因为它什么都不做)。我向你保证我有正当理由这么做。什么好主意吗?
没有直接的方法来确定当前实例是否已经覆盖了您的虚拟方法。这可能需要一些非常讨厌的、不可维护的代码,比如通过反射检查方法体声明类型,看看那里有什么。
话虽如此,我强烈质疑这里的设计目标。你的问题基本上是要求一种特定的方式来违反Liskov替代原则,这是面向对象编程的核心原则之一。这将使你的代码性能下降,更难以维护…
Reflection是这个问题的一个很好的答案。
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(),除非它没有被覆盖。
检查一下:检测方法是否被反射(c#)覆盖
反射将是在运行时执行此操作的唯一方法。这应该附带一个健康警告,但是,从OOP的角度来看,它应该被认为是一个非常糟糕的主意™。基类通常不应该知道或关心派生类是如何实现的。
有几个选项:
如果派生类必须实现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;
Update:这里提供的链接比必要的更详细,但也不完整。上面的版本也适用于受保护的方法和虚拟属性(这就是为什么您使用GetMember
而不是限制性更强的GetMethod
),这两个链接都没有地址。