C# 如何覆盖现有的扩展方法

C# 如何覆盖现有的扩展方法,c#,asp.net-mvc,C#,Asp.net Mvc,我想用我自己的方法替换.NET或ASP MVC框架中包含的扩展方法 范例 public static string TextBox(this HtmlHelper htmlHelper, string name) { ... } 可能吗?我无法使用override或new关键字。扩展方法不能被覆盖,因为它们不是实例方法,也不是虚拟的 如果您通过命名空间导入这两个扩展方法类,编译器会抱怨,因为它不知道要调用哪个方法: 以下方法或属性之间的调用不明确: 唯一的解决方法是使用普通的静态方法语法

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

范例

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

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

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

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

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

唯一的解决方法是使用普通的静态方法语法调用扩展方法。因此,与此相反:

a.Foo();
您必须这样做:

YourExtensionMethodClass.Foo(a);
namespace FrobCo
{
  using BazCo.TheirExtensionNamespace;
  namespace Blorble
  {
    using FrobCo.MyExtensionNamespace;
    ... some extension method call
  }

扩展方法基本上只是静态方法,所以我不知道如何重写它们,但是如果您只是将它们放在不同的名称空间中,那么您可以调用自己的名称空间,而不是要替换的名称空间

但是Matt Manela谈到实例方法如何优先于扩展方法:

有关扩展方法的更多信息,请参见

编辑:我忘记了模糊性问题,所以最好不要包含要替换的扩展方法。因此,您可能不需要使用'using'指令,而只需要输入某些类的整个包名,这就可以解决问题。

更新:这个问题是。谢谢你的提问


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

确定哪种方法是“最佳”方法涉及到许多因素;不同的语言使用不同的“混合”因素来解决这个问题。C#特别强调给定方法与调用站点的“接近度”。如果让C#在基类中的一个适用方法或派生类中的一个新的适用方法之间进行选择,则C#会选择派生类中的一个,因为它更接近,即使基类中的一个在其他方面更匹配

所以我们列出了清单。派生类比基类更接近。内部类比外部类更接近。类层次结构中的方法比扩展方法更接近

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

例如,如果你有

namespace FrobCo.Blorble
{
  using BazCo.TheirExtensionNamespace;
  using FrobCo.MyExtensionNamespace;
  ... some extension method call
}
然后是模棱两可的,越近越好。如果你想优先考虑你的,而不是他们的,你可以选择这样做:

YourExtensionMethodClass.Foo(a);
namespace FrobCo
{
  using BazCo.TheirExtensionNamespace;
  namespace Blorble
  {
    using FrobCo.MyExtensionNamespace;
    ... some extension method call
  }
现在,当重载解析用于解析扩展方法调用时,
Blorple
get中的类首先执行,然后是
FrobCo.MyExtensionNamespace
中的类,然后是
FrobCo
中的类,然后是
BazCo.TheirExtensionNamespace中的类

清楚吗?

基于Eric的前提(以及视图代码被呈现到ASP命名空间的事实),您应该能够像这样覆盖它(至少它在ASP.NET MVC4.0中对我有效)

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”。

设计上不可能覆盖扩展方法。以下是两种可能的解决方法:

1.)使用更具体的类型

当然,只有当目标类型比现有扩展方法的类型更具体时,才能使用此方法。此外,可能需要对所有适用类型执行此操作

// "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();
//通过使用更具体的类型“重写”默认Linq方法
公共静态bool Any(此列表源)
{
返回可枚举的.Any(源);
}
//这将调用您的扩展方法
新列表().Any();
2.)添加虚拟参数

没有那么漂亮。此外,这将要求您修改现有调用以包含伪参数

// 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);
//当指定“override”时,将调用此方法,而不是默认的Linq方法
公共静态bool Any(此IEnumerable源,bool@override=true)
{
返回source.Any();
}
//这将调用您的扩展方法
新列表().Any(true);

正如Eric指出的,它并没有导入两个不同的匹配扩展方法,而是在相同的嵌套级别上导入它们。我相信他说的是用不同的行为覆盖一个方法的行为,而不是多态行为这里有一个问题,我怎么能在为我的类创建的扩展方法之上隐藏我的类方法?e、 Deer类有Run方法,我想确保当我在“Mars”名称空间(类MarsLand)中使用Deer时,我想确保在Mars名称空间的扩展方法中声明的Run方法将被调用。Deer是名称空间Earth的一部分。@Dhananjay:类层次结构中的适用方法总是胜过扩展方法。如果需要调用扩展方法,请将其作为静态方法调用。为什么
FrobCo.MyExtensionNamespace
FrobCo.Blorble
中的任何类都比不上
BazCo.TheirExtensionNamespace
?在我看来,对于BazCo扩展,您需要上升两个名称空间级别,然后下降两个其他级别,而对于FrobCo扩展,您只需要上升然后下降一个名称空间级别。因此,对我来说,FrobCo扩展似乎更接近。难以置信。在阅读这个答案的几分钟内,我学会了3到4件事。从技术上讲,这不是一个过载吗?@marsze Yea,但问题是关于覆盖而不是过载。