繁体   English   中英

如何覆盖现有的扩展方法

[英]How to override an existing extension method

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

例子

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

是否有可能? 我不能使用 override 或 new 关键字。

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


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

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

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

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

例如,如果你有

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

那么哪个更接近是不明确的。 如果你想优先考虑你的而不是他们的,你可以选择这样做:

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

而现在,当重载决议去解决扩展方法调用,在班Blorple得到第一次去,然后在课堂上FrobCo.MyExtensionNamespace ,然后在课堂上FrobCo ,然后班BazCo.TheirExtensionNamespace

明白了吗?

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

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

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

解决此问题的唯一方法是使用正常的静态方法语法调用您的扩展方法。 所以而不是这个:

a.Foo();

你必须这样做:

YourExtensionMethodClass.Foo(a);

基于 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));
    }
  }
}

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

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

但是 Matt Manela 谈到了实例方法如何优先于扩展方法: 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/

编辑:我忘记了歧义问题,所以最好的办法是尽量不包括要替换的扩展方法。 因此,您可能不需要使用 'using' 指令,而只需输入某些类的整个包名称,这样就可以解决问题。

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

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();

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);

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM