簡體   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