110

There have been occasions where I would want to override a method in a class with an extension method. Is there any way to do that in C#?

For example:

public static class StringExtension
{
    public static int GetHashCode(this string inStr)
    {
        return MyHash(inStr);
    }
}

A case where I've wanted to do this is to be able to store a hash of a string into a database and have that same value be used by all the classes that use the string class's hash (i.e. Dictionary, etc.) Since the built-in .NET hashing algorithm is not guaranteed to be compatible from one version of the framework to the next, I want to replace it with my own.

There are other cases I've run into where I'd want to override a class method with an extension method as well so it's not just specific to the string class or the GetHashCode method.

I know I could do this with subclassing off an existing class but it would be handy to be able to do it with an extension in a lot of cases.

Amal K
  • 4,359
  • 2
  • 22
  • 44
Phred Menyhert
  • 2,420
  • 4
  • 19
  • 19
  • Since a Dictionary is an in-memory data structure, what difference does it make whether the hashing algorithm changes from on version of the framework to the next? If the framework version changes, then obviously the application has been restarted and the dictionary has been re-built. – David Nelson May 22 '09 at 19:23

4 Answers4

101

No; an extension method never takes priority over an instance method with a suitable signature, and never participates in polymorphism (GetHashCode is a virtual method).

Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900
  • "...never participates in polymorphism (GetHashCode is a virtual method)" Could you explain in an other way why an extension method would never participate in polymorphism due to it being virtual? I'm having problems seeing the connection with those two statements. – Alex May 31 '14 at 06:08
  • 3
    @Alex by mentioning virtual I am simply clarifying what it means to be polymorphic. In virtually all uses of GetHashCode, the concrete type is unknown - so polymorphism is in play. As such, extension methods wouldn't help **even if they took priority** in the regular compiler. What the OP really wants is monkey-patching. Which c# and .net do not facilitate. – Marc Gravell May 31 '14 at 07:04
  • 4
    That is sad, in C# so many misleading non-sense methods, like e.g. `.ToString()` in arrays. It is definitely a needed feature. – Hi-Angel Sep 02 '15 at 08:43
  • Why don't you get a compiler error then? E.g. I type. `namespace System { public static class guilty { public static string ToLower(this string s) { return s.ToUpper() + " I'm Malicious"; } } }` – LowLevel Jun 09 '18 at 11:10
  • @LowLevel why would you? – Marc Gravell Jun 09 '18 at 15:28
8

If the method has a different signature, then it can be done -- so in your case: no.

But otherwise you need to use inheritance to do what you are looking for.

Chris Brandsma
  • 11,666
  • 5
  • 47
  • 58
2

As far as I know the answer is no, because an extension method is not an instance.It's more like an intellisense facility to me that let you call a static method using an instance of a class. I think a solution to your problem can be an interceptor that intercepts the execution of a specific method (e.g. GetHashCode()) and do something else.To use such an interceptor (like the one Castle Project provides) all objects should be instansiated using an object factory (or an IoC container in Castle) so that thier interfaces can be intercepted through a dynamic proxy generated in runtime.(Caslte also lets you intercept virtual members of classes)

Beatles1692
  • 5,214
  • 34
  • 65
0

I have found a way to invoke an extension method with the same signature as a class method, however it does not seem very elegant. When playing around with extension methods I noticed some undocumented behavior. Sample code:

public static class TestableExtensions
{
    public static string GetDesc(this ITestable ele)
    {
        return "Extension GetDesc";
    }

    public static void ValDesc(this ITestable ele, string choice)
    {
        if (choice == "ext def")
        {
            Console.WriteLine($"Base.Ext.Ext.GetDesc: {ele.GetDesc()}");
        }
        else if (choice == "ext base" && ele is BaseTest b)
        {
            Console.WriteLine($"Base.Ext.Base.GetDesc: {b.BaseFunc()}");
        }
    }

    public static string ExtFunc(this ITestable ele)
    {
        return ele.GetDesc();
    }

    public static void ExtAction(this ITestable ele, string choice)
    {
        ele.ValDesc(choice);
    }
}

public interface ITestable
{

}

public class BaseTest : ITestable
{
    public string GetDesc()
    {
        return "Base GetDesc";
    }

    public void ValDesc(string choice)
    {
        if (choice == "")
        {
            Console.WriteLine($"Base.GetDesc: {GetDesc()}");
        }
        else if (choice == "ext")
        {
            Console.WriteLine($"Base.Ext.GetDesc: {this.ExtFunc()}");
        }
        else
        {
            this.ExtAction(choice);
        }
    }

    public string BaseFunc()
    {
        return GetDesc();
    }
}

What I noticed was that if I called a second method from inside an extension method, it would call the extension method that matched the signature even if there was a class method that also matched the signature. For example in the code above, when I call ExtFunc(), which in turn calls ele.GetDesc(), I get the return string "Extension GetDesc" instead of the string "Base GetDesc" that we would expect.

Testing the code:

var bt = new BaseTest();
bt.ValDesc("");
//Output is Base.GetDesc: Base GetDesc
bt.ValDesc("ext");
//Output is Base.Ext.GetDesc: Extension GetDesc
bt.ValDesc("ext def");
//Output is Base.Ext.Ext.GetDesc: Extension GetDesc
bt.ValDesc("ext base");
//Output is Base.Ext.Base.GetDesc: Base GetDesc

This allows you to bounce back and forth between class methods and extension methods at will, but requires the addition of duplicate "pass-through" methods to get you into the "scope" you desire. I am calling it scope here for lack of a better word. Hopefully someone can let me know what it is actually called.

You might have guessed by my "pass-through" method names that I also toyed with the idea of passing delegates to them in the hopes that a single method or two could act as a pass-through for multiple methods with the same signature. Unfortunately it was not to be as once the delegate was unpacked it always chose the class method over the extension method even from inside another extension method. "Scope" no longer mattered. I have not used Action and Func delegates very much though so maybe someone more experienced could figure that part out.

DanK
  • 59
  • 7