How to detect if virtual method is overridden in c# [duplicate]
Asked Answered
R

5

14

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?

Rousseau answered 29/8, 2011 at 18:0 Comment(7)
Perhaps you could clarify the question as it's not the case that the compiler allows unimplemented virtual methods? Your code will not compile.Albano
@James Gaunt, you are, of course, correct. For some reason Visual Studio wasn't giving me any syntactical error, leading me to believe it was acceptable code. However, when I ran the code, it failed. I have corrected the question.Rousseau
Ahh! Now your asking a totally different question. Check this out #2932921 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 (tm) from an OOP perspective.Albano
Thanks James, that's what I'm looking for. If you submit that as an answer, I'll give you credit. (And your right again, I really did ask the wrong question to begin with. :)Rousseau
anything that derives from the base class is going to have to implement the method, so if your code is getting called, the method has been overridden; unless, of course, you mean something else by "is implemented"? [edit: well, to clarify, anything that has been instantiated, that derives from the base class...]Gummous
@threed -- although the answer James provided might work (with modification), there is a more straightforward way to do this. I don't need the vote, but at least check out my solution.Nigrify
I know this is an old question, but if the base implementation isn't doing anything, a smarter way might be to provide an optional interface, and then the base class can say "if (this is IDoSomethingExtra) ((IDoSomethingExtra)this).DoSomethingExtra(p)". Much cleaner than using reflection to detect who implemented what method.Keefer
A
3

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.

Albano answered 29/8, 2011 at 18:21 Comment(0)
B
10

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...

Bend answered 29/8, 2011 at 18:2 Comment(3)
Your question is basically asking for a specific way to violate the Liskov Substitution Principle Not really. ADerived is still perfectly substitutable for ABase. And per James Gaunt's comment, there is a pretty clean way of using reflection to determine which class the implementation of the virtual method is coming from.Rousseau
@threed: You're trying to change the behavior based on the runtime type of the object. This is causing the behavior of your method to differ if ADerived is passed instead of ABase, which violates LSP...Bend
To alter the behavior of a method, even in a base class, based on the type passed is not in violation of LSP: '...that is, if S is a subtype of T, then objects of type T in a program may be replaced with objects of type S without altering any of the desirable properties of that program (e.g., correctness).' linkRousseau
D
9

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.

Dactylogram answered 29/8, 2011 at 18:28 Comment(1)
Thanks for actually answering the question asked. This works like a charm.Secondly
A
3

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.

Albano answered 29/8, 2011 at 18:21 Comment(0)
A
2

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.

Azrael answered 29/8, 2011 at 18:3 Comment(4)
+1 just because it seems harsh this got a downvote without any explanation!Albano
The flag seems like unnecessary information, when an empty implementation works just as well. Requiring a flag to be set would dramatically reduce maintainability, as a method override is expected to work...Bend
@Reed I agree, which is why I added the comment at the end indicating that the empty implementation is best.Azrael
Along these lines, in some cases you can flip the logic around so that the overrider doesn't have to "remember" to set a flag: if you control all the call sites, and especially is they're all from the base class itself, you can adopt a convention where overriders never call the virtual base. Then, you set a private flag before each call, and always clear it in the virtual function base. If it's still set when the call returns, it was overridden. As noted, this sort of thing is fragile, but doing it this way can make the overiders cleaner. Note that this isn't thread-safe as described.Under
N
2

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.

Nigrify answered 29/8, 2011 at 18:25 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.