ozanbora
ozanbora

Reputation: 138

Extension Method Overriding

Let's assume that I have two class.

public class A {...} 
public class B : A {...}

What I want is to achieve is to override an extension function for both type.

public static void HelperExtension(this A a) {...}
public static void HelperExtension(this B b) {...}

I know that they are not virtual functions or behave like them. However I really wonder compiler behavior in this case.

Is there a way to call the function for type B without resolving its type? Or any auto-resolve suggestions?

Upvotes: 5

Views: 3024

Answers (3)

Massimo Perrone
Massimo Perrone

Reputation: 1

I recently faced a similar problem. I have a third-party class library containing a hierarchy of class (let's say IBase, Base and Derived, where IBase is actually an interface).

public interface IBase {...}
public class Base : IBase {...}
public class Derived : Base {...}

Then, I have a class of mine which holds a reference ext to IBase. The concrete type of ext may be Base as well as Derived.

public class MyClass {
    // other stuff
    public IBase ext;
}

What I actually needed was a virtual method AddedMethod() defined within IBase and overridden in each descendant class, but that wasn't viable. So, one could be tempted to define a class containing a set of overloaded extension methods:

public static class MyExtensions
{
    public static void AddedMethod(this IBase arg) {...}
    public static void AddedMethod(this Base arg) {...}
    public static void AddedMethod(this Derived arg) {...}
}

then, call ext.AddedMethod() on MyClass objects. This doesn't work: as extension methods are statically bound, the first method (i.e. AddedMethod(this IBase arg)) gets always called, regardless the actual type of ext. The problem can be bypassed by defining a single extension method on IBase, then by using reflection to select the correct instance of a private static method whose argument type matches the actual type passed to the extension method:

public static class MyExtensions
{
    // just one extension method
    public static void AddedMethod(this IBase arg){
        // get actual argument type
        Type itsType = arg.GetType();

        // select the proper inner method
        MethodInfo mi = typeof(MyExtensions).GetMethod("innerAddedMethod",
            BindingFlags.NonPublic | BindingFlags.Static,
            null,
            new Type[] { itsType },
            null);

        // invoke the selected method
        if (mi != null) {
            mi.Invoke(null, new object[] { arg });
        }
    }

    private static void innerAddedMethod(Base arg) {
        // code for Base type arg 
    }

    private static void innerAddedMethod(Derived arg) {
        // code for Derived type arg
    }

Whether a new derived class Derived2 should be added to the IBase hierarchy, we'll have to simply add to MyExtensions class an overloaded innerAddedMethod() which takes Derived2 as its argument.

Upvotes: 0

Servy
Servy

Reputation: 203804

As you said, there is no way of just making the extension virtual.

You could implement the entire virtual method pattern yourself through static methods but I have a strong feeling that's not going to be of any practical use to you, it's more of an interesting theoretical solution as the work involved would be prohibitive for something this simple.

If there are a fixed, finite number of possible sub classes you could have the first method have something like:

public static void HelperExtension(this A a)
{
    B b = a as B;
    if(b != null)
       HelperExtension(b);
    else
       //the rest of the method.
}

You could use a Switch or even a Dictionary<Type, Action<A>> if you have a lot of subclasses, but it would be tedious, hard to maintain, and not support arbitrary inheritors not known at compile time.

Another option is to essentially leverage the compiler's functionality at compile time through the use of dynamic. I strongly advice avoiding it whenever possible, but in this particular case it would allow you to have a single public extension on A, a bunch of private static methods (with a different name) for each sub type, and then a single dispatch call:

public static void HelperExtension(this A a)
{
    ExtenstionImplementation((dynamic)a);
}

private static void ExtenstionImplementation(A a){...}
private static void ExtenstionImplementation(B a){...}
private static void ExtenstionImplementation(C a){...}

Upvotes: 2

Oded
Oded

Reputation: 498914

This is not overriding - it is overloading, if anything.

It is fine - since the signatures are different, the compiler will not have any problem compiling it, even in the same namespace.

However, which extension method will be called depends on the exact type of the variable.


Now:

Is there a way to call the function for type B without resolving its type? Or any auto-resolve suggestions?

Without casting this is not possible. The extension is bound to the exact type that is being extended, so you need to have the exact type in order to call an extension on it.

This is why most of LINQ is defined on IEnumerable<T>.

Upvotes: 5

Related Questions