How to override an existing extension method

C#asp.net Mvc

C# Problem Overview


I want to replace extension methods included in the .NET or ASP MVC framework by my own methods.

Example

public static string TextBox(this HtmlHelper htmlHelper, string name)
{
   ...
}

Is it possible? I can't use the override or new keyword.

C# Solutions


Solution 1 - C#

UPDATE: This question was the subject of my blog in December of 2013. Thanks for the great question!


You can do this, in a sense. But I should start by talking briefly about the basic design principle of overload resolution in C#. All overload resolution is, of course, about taking a set of methods with the same name and choosing from that set the unique best member to call.

There are many factors involved in determining which is the "best" method; different languages use a different "mixture" of factors to figure this out. C# in particular heavily weights "closeness" of a given method to the call site. If given the choice between an applicable method in a base class or a new applicable method in a derived class, C# takes the one in the derived class because it is closer, even if the one in the base class is in every other way a better match.

And so we run down the list. Derived classes are closer than base classes. Inner classes are closer than outer classes. Methods in the class hierarchy are closer than extension methods.

And now we come to your question. The closeness of an extension method depends on (1) how many namespaces "out" did we have to go? and (2) did we find the extension method via using or was it right there in the namespace? Therefore you can influence overload resolution by changing in what namespace your static extension class appears, to put it in a closer namespace to the call site. Or, you can change your using declarations, to put the using of the namespace that contains the desired static class closer than the other.

For example, if you have

namespace FrobCo.Blorble
{
  using BazCo.TheirExtensionNamespace;
  using FrobCo.MyExtensionNamespace;
  ... some extension method call
}

then it is ambiguous which is closer. If you want to prioritize yours over theirs, you could choose to do this:

namespace FrobCo
{
  using BazCo.TheirExtensionNamespace;
  namespace Blorble
  {
    using FrobCo.MyExtensionNamespace;
    ... some extension method call
  }

And now when overload resolution goes to resolve the extension method call, classes in Blorple get first go, then classes in FrobCo.MyExtensionNamespace, then classes in FrobCo, and then classes in BazCo.TheirExtensionNamespace.

Is that clear?

Solution 2 - C#

Extension methods cannot be overridden since they are not instance methods and they are not virtual.

The compiler will complain if you import both extension method classes via namespace as it will not know which method to call:

> The call is ambiguous between the following methods or properties: ...

The only way around this is to call your extension method using normal static method syntax. So instead of this:

a.Foo();

you would have to do this:

YourExtensionMethodClass.Foo(a);

Solution 3 - C#

Based on Eric premise (and the fact that views code is rendered into ASP namespace) you should be able to override it like this (at least it works for me in ASP.NET MVC4.0 Razor

using System.Web.Mvc;

namespace ASP {
  public static class InputExtensionsOverride {
    public static MvcHtmlString TextBox(this HtmlHelper htmlHelper, string name) {
      TagBuilder tagBuilder = new TagBuilder("input");
      tagBuilder.Attributes.Add("type", "text");
      tagBuilder.Attributes.Add("name", name);
      tagBuilder.Attributes.Add("crazy-override", "true");
      return new MvcHtmlString(tagBuilder.ToString(TagRenderMode.Normal));
    }
  }
}

Note the namespace has to be "ASP".

Solution 4 - C#

Extension methods are basically just static methods so I don't know how you can override them, but if you just put them in a different namespace then you can call yours instead of the one you want to replace.

But Matt Manela talks about how instance methods have precedence over extension methods: http://social.msdn.microsoft.com/forums/en-US/csharplanguage/thread/e42f1511-39e7-4fed-9e56-0cc19c00d33d

For more ideas about extension methods you can look at http://gen5.info/q/2008/07/03/extension-methods-nulls-namespaces-and-precedence-in-c/

Edit: I forgot about the ambiguity issue, so your best bet is to try not including the extension methods you want to replace. So, you may need to not use the 'using' directive but just put in the entire package name of some classes, and this could solve the problem.

Solution 5 - C#

Overriding extension methods is not possible by design. Here are 2 possible workarounds:

1.) Use a more specific type

This can only be used of course if the target type is more specific than that of the existing extension method. Also, it might be necessary to do this for all applicable types.

// "override" the default Linq method by using a more specific type
public static bool Any<TSource>(this List<TSource> source)
{
    return Enumerable.Any(source);
}

// this will call YOUR extension method
new List<T>().Any();

2.) Add a dummy parameter

Not as pretty. Also, this will require you to modify existing calls to include the dummy argument.

// this will be called instead of the default Linq method when "override" is specified
public static bool Any<TSource>(this IEnumerable<TSource> source, bool @override = true)
{
    return source.Any();
}

// this will call YOUR extension method
new List<T>().Any(true);

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionMiniScalopeView Question on Stackoverflow
Solution 1 - C#Eric LippertView Answer on Stackoverflow
Solution 2 - C#Andrew HareView Answer on Stackoverflow
Solution 3 - C#Ondrej SvejdarView Answer on Stackoverflow
Solution 4 - C#James BlackView Answer on Stackoverflow
Solution 5 - C#marszeView Answer on Stackoverflow