如何覆盖现有的扩展方法

Min*_*ope 59 c# asp.net-mvc

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

public static string TextBox(this HtmlHelper htmlHelper, string name)
{
   ...
}
Run Code Online (Sandbox Code Playgroud)

可能吗?我无法使用override或new关键字.

Eri*_*ert 102

更新:这个问题是我2013年12月的博客主题.谢谢你这个好问题!


从某种意义上说,你可以做到这一点.但我首先要简单谈谈C#中重载解析的基本设计原则.当然,所有重载决策都是关于采用一组具有相同名称的方法,并从该组中选择要调用的唯一最佳成员.

确定哪种是"最佳"方法涉及许多因素; 不同的语言使用不同的"混合"因素来解决这个问题.C#特别重视给定方法对呼叫站点的"接近度".如果在基类中的适用方法或派生类中的新适用方法之间进行选择,C#将获取派生类中的一个,因为它更接近,即使基类中的那个更好,也是更好的比赛.

所以我们在列表中运行.派生类比基类更接近.内部类比外部类更接近.类层次结构中的方法比扩展方法更接近.

现在我们来回答你的问题.扩展方法的接近程度取决于(1)我们必须使用多少名称空间"out"?(2)我们是否通过using命名空间找到了扩展方法?因此,您可以通过更改静态扩展类出现的命名空间来影响重载决策,将其放在调用站点的更近的命名空间中.或者,您可以更改using声明,using使包含所需静态类的命名空间比另一个更接近.

例如,如果你有

namespace FrobCo.Blorble
{
  using BazCo.TheirExtensionNamespace;
  using FrobCo.MyExtensionNamespace;
  ... some extension method call
}
Run Code Online (Sandbox Code Playgroud)

然后它更模糊,更接近.如果您想优先考虑他们的优先级,您可以选择这样做:

namespace FrobCo
{
  using BazCo.TheirExtensionNamespace;
  namespace Blorble
  {
    using FrobCo.MyExtensionNamespace;
    ... some extension method call
  }
Run Code Online (Sandbox Code Playgroud)

现在,当重载决策去解析扩展方法调用时,Blorple先获取get类FrobCo.MyExtensionNamespace,然后是类,然后是类FrobCo,然后是类BazCo.TheirExtensionNamespace.

明白了吗?

  • @Dhananjay:类层次结构中的适用方法*总是*胜过扩展方法.如果需要调用扩展方法,请将其作为静态方法调用. (3认同)

And*_*are 28

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

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

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

解决此问题的唯一方法是使用常规静态方法语法调用扩展方法.所以不是这样的:

a.Foo();
Run Code Online (Sandbox Code Playgroud)

你必须这样做:

YourExtensionMethodClass.Foo(a);
Run Code Online (Sandbox Code Playgroud)


Ond*_*dar 5

基于 Eric 前提(以及视图代码呈现到 ASP 命名空间的事实),您应该能够像这样覆盖它(至少它在 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));
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

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