如何覆盖现有的扩展方法

我想用自己的方法来replace.NET或ASP MVC框架中包含的扩展方法。

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

可能吗? 我无法使用覆盖或新的关键字。

更新:这个问题是我的博客在2013年12月的主题 。 感谢您的好问题!


从某种意义上说,你可以做到这一点。 但是我应该先简单地谈谈C#中重载分辨率的基本devise原理。 当然,所有的重载解决scheme都是采用一组具有相同名称的方法,并从中select唯一的最佳成员来进行调用。

确定哪一个是最好的方法有很多因素, 不同的语言使用不同的“混合”因素来解决这个问题。 C#特别重视给定方法到呼叫站点的“接近度”。 如果在基类中的适用方法或派生类中的新适用方法之间进行select,则C#将在派生类中使用该方法,因为它更接近,即使基类中的方法更好比赛。

所以我们把这个名单放下。 派生类比基类更近。 内部类比外部类更近。 类层次中的方法比扩展方法更接近。

现在我们来谈谈你的问题。 扩展方法的紧密程度取决于(1)我们必须去“多less”命名空间? (2)我们是否通过using名称空间或在名称空间中find扩展方法? 因此,您可以通过更改静态扩展类出现的名称空间来影响重载parsing,从而将其置于更靠近呼叫站点的命名空间中。 或者,你可以改变你的using声明,把包含所需静态类的命名空间的using比另一个更接近。

例如,如果你有

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

那么这是更接近暧昧的。 如果你想优先考虑他们的,你可以select这样做:

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

而现在当重载决议去解决扩展方法调用时, Blorple类首先进入,然后是FrobCo.MyExtensionNamespace类,然后是FrobCo类,然后是FrobCo类。

这清楚吗?

扩展方法不能被覆盖,因为它们不是实例方法,也不是虚拟的。

如果您通过名称空间导入两个扩展方法类,编译器将会抱怨,因为它不知道要调用哪个方法:

以下方法或属性之间的调用是不明确的:…

唯一的解决办法是使用普通的静态方法语法来调用你的扩展方法。 所以,而不是这个:

 a.Foo(); 

你将不得不这样做:

 YourExtensionMethodClass.Foo(a); 

扩展方法基本上只是静态方法,所以我不知道如何覆盖它们,但是如果你把它们放在不同的名字空间,那么你可以调用你的而不是你想要replace的那个。

但马特·马内拉谈到如何实例方法优先于扩展方法: http ://social.msdn.microsoft.com/forums/en-US/csharplanguage/thread/e42f1511-39e7-4fed-9e56-0cc19c00d33d

有关扩展方法的更多信息,请参阅http://gen5.info/q/2008/07/03/extension-methods-nulls-namespaces-and-precedence-in-c/

编辑:我忘了歧义问题,所以你最好的select是尝试不包括你想要replace的扩展方法。 所以,你可能不需要使用'using'指令,只需要放入一些类的整个包名就可以解决问题。

根据Eric的前提(以及视图代码被渲染到ASP命名空间的事实),你应该能够像这样覆盖它(至less在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)); } } } 

注意命名空间必须是“ASP”。