3

The very act of asking this question suggests that my approach to this problem is incorrect, so I'm interested in answers which address the question directly, as well as answers which suggest a cleaner approach to what I'm doing.

Consider a base class which provides a standard set of services and functionalities, as well as some structure around those. By way of metaphor, let's consider the following example class:

public class ExampleBase
{
  public void Main()
  {
    // Do something
    PreValidate(); // Extensibility point for derived classes
    // Do something else
    PostValidate(); // Extensibility point for derived classes
    // Do something else 
  }

  protected virtual void PreValidate()
  {
  }

  protected virtual void PostValidate()
  {
  }
}

The derived class can now override these virtual methods to provide some custom logic.

Here is the question: Is it possible for the base class to discover at runtime if the derived class has taken the liberty of overriding one of these virtual methods, before invoking the virtual method?

(If it was sufficient to know the answer to this question after invoking the method, then you could perhaps replace the empty method in the base class with a method that sets a private flag, which would indicate the method was not overridden. However this might be fooled if the derived class invokes base.PreValidate() in its overridden implementation.)

Perhaps the best solution would be to use a completely different extensibility mechanism if this level of flexibility is required?

Daniel Fortunov
  • 43,309
  • 26
  • 81
  • 106

8 Answers8

9

While the best way to solve this problem is mentioned in other answers, I answer the question title (this will handle the new issue):

var isOverridden = 
   new Action(MethodName).Method.DeclaringType != typeof(BaseClass);
// Replace `Action` with any conforming delegate type.

This trick makes the CLR method dispatch mechanism to find the MethodInfo for us, instead of resorting to reflection to find it.

Mehrdad Afshari
  • 414,610
  • 91
  • 852
  • 789
  • 1
    Sneaky! Didn't know that was possible but yes that allows you to get around all manner of reflection and "new" issues. – JaredPar May 08 '09 at 14:37
2

Is it possible to determine if method X is overriden at runtime

Yes, but as you've already pointed out you probably don't want to. You can use this.GetType() + reflection magic to look for defined methods in the derived class which override the current base. This is extremely expensive and tricky as you have to consider overloads, deep hierarchies and other fun generic issues.

EDIT

For a way to do this without using Reflection, see Mehrdad's answer.

What should you do differently?

You should separate this method into 2 parts.

  1. The part that you absolutely depend on running. Make this a non-virtual method so derived classes cannot interfere with it
  2. The extensibility portion. Make this a virtual protected method called from #1.

For example

protected void PreValidate() {
  .. my validation code
  PreValidateImpl();
}

protected virtual void PreValidateImpl() {
  // Nothing by default
}
Mehrdad Afshari
  • 414,610
  • 91
  • 852
  • 789
JaredPar
  • 733,204
  • 149
  • 1,241
  • 1,454
1

You could do this:

public abstract class ExampleBase
{
  public void Main()
  {
    // Do something
    PreValidate(); // Extensibility point for derived classes
    // Do something else
    PostValidate(); // Extensibility point for derived classes
    // Do something else 
  }

  protected abstract void PreValidate();

  protected abstract void PostValidate();

}

This would force all derived types to override the methods. You are probably better off not checking this kind of thing at execution time - using an abstract type and abstract methods you are allowing the compiler to do the lifting for you to ensure that all consumers of your type override the methods.

If having the type be abstract does not work then you could always do something like this:

public class ExampleBase
{
    public void Main()
    {
        // Do something
        PreValidate(); // Extensibility point for derived classes
        // Do something else
        PostValidate(); // Extensibility point for derived classes
        // Do something else 
    }

    protected virtual void PreValidate()
    {
        throw new NotImplementedException();
    }

    protected virtual void PostValidate()
    {
        throw new NotImplementedException();
    }
}

But this approach moves any potential errors from compile-time to execution-time which is best avoided at all costs.

Andrew Hare
  • 344,730
  • 71
  • 640
  • 635
1

Of course! You will have to use reflection.

if (this.GetType().GetMethod("PreValidate").DeclaringType ==
        typeof(ExampleBase))
{
    // Not overridden
}
else
{
    // Overridden
}

Keep in my that reflection is a bit slow so you don't want to execute that, say for instance, a million times a second.

Tamas Czinege
  • 118,853
  • 40
  • 150
  • 176
  • This works for simple example but needs more rigor to be generally usable. You need to consider both overloads and "new" methods vs. virtual overrides. – JaredPar May 08 '09 at 14:22
  • @JaredPar: in this particular example, both methods were called from the base class. "new" methods do not get invoked if a method with the same signature is invoked from the base class - that's the point of "new" methods, they don't cause conflicts. – Tamas Czinege May 08 '09 at 14:27
  • @DrJokepu, You're not checking for invocation though, you're checking for definition. I could make this return true by defining the following method on my base class "private new void PreValidate()". This would cause your check to return "true" when in fact I did not override anything. – JaredPar May 08 '09 at 14:29
1

It seems like your PreValidate() and PostValidate() would be better served as a different type of extension model. A provider model where these are injected as delegates or full objects satisfying a specific interface might be more suited to your desire to be able to inspect the state of those services at runtime.

Tetsujin no Oni
  • 7,300
  • 2
  • 29
  • 46
1

You can emulate this with interfaces:

public interface ISupportPreValidate
{
    void PreValidate();
}

public interface ISupportPostValidate
{  
    void PostValidate();
}

public class Base
{
    public void Validate()
    {
        if(this is ISupportPreValidate)
            ((ISupportPreValidate)this).PreValidate();

        // Validation logic

        if(this is ISupportPostValidate)
            ((ISupportPostValidate)this).PostValidate();            
    }
}

And then implement required interfaces in Base-derived classes.

Anton Gogolev
  • 113,561
  • 39
  • 200
  • 288
0

Ask yourself the following:

  1. Will I ever create an object from ExampleBase? Or will I always inherit from this class instead and create an object from an inherited class?
  2. Is PreValidate and PostValidate required methods of any derived class?

Point being, it looks from your design that you should really be creating an abstract class, with abstract methods, not virtual methods. Also, from your description it seems that's what you're trying to get at as well.

public abstract class ExampleBase
{
    public void Main()
    {
        // Do something
        PreValidate(); // Extensibility point for derived classes
        // Do something else
        PostValidate(); // Extensibility point for derived classes
        // Do something else 
    }

    protected abstract void PreValidate();

    protected abstract void PostValidate();
}

This way the derived classes are FORCED to define these methods.

Joseph
  • 25,330
  • 8
  • 76
  • 125
0

JaredPar's alternate approach is good, though events are IMHO cleaner for extensibility.

protected event ThreadStart OnPreValidate;

protected void PreValidate()
{
  .. my validation code
  if (null != OnPreValidate) {
    OnPreValidate();
  }
}
Lachlan Roche
  • 25,678
  • 5
  • 79
  • 77