2009-09-20 9 views
52

.NETまたはASP MVCフレームワークに含まれる拡張メソッドを自分のメソッドで置き換えたいと思っています。既存の拡張メソッドをオーバーライドする方法

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

それは可能ですか? overrideやnewキーワードは使用できません。

答えて

93

更新:この質問はthe subject of my blog in December of 2013でした。素晴らしい質問をありがとう!


これは、ある意味でこれを行うことができます。しかし、まず、C#のオーバーロード解決の基本的な設計原則について簡単に説明します。すべてのオーバーロードの解決は、もちろん、同じ名前のメソッドのセットを取り、一意の最良メンバーを呼び出すセットから選択することです。

"ベスト"方法の決定には多くの要因があります。異なる言語は、これを把握するためにさまざまな "要素の混合"を使用します。 C#では、コール・サイトに対する特定のメソッドの「近さ」を重視しています。ベースクラスの適用可能なメソッドか、派生クラスの新しい適用可能なメソッドのどちらかを選択した場合、C#は、ベースクラスのものが他の方法よりも優れている場合であっても、一致。

リストを実行します。派生クラスは基本クラスよりも近い。内部クラスは外部クラスよりも近い。クラス階層のメソッドは、拡張メソッドよりも近いです。

あなたの質問にお答えします。拡張メソッドの親密性は、(1)いくつの名前空間を "out"しなければならないかにかかっていますか? (2)拡張メソッドがusingで見つかったのですか、それとも名前空間に正しくありましたか?したがって、静的拡張クラスが表示されるネームスペースを変更して、コールサイトに近い名前空間に配置することで、オーバーロードの解決に影響を与えることができます。または、using宣言を変更して、目的の静的クラスを含む名前空間のusingをもう一方の静的クラスに近づけることができます。例えば

、あなたが

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

を持っている場合は、近いいるあいまいです。オーバーロードの解決は、拡張メソッドの呼び出しを解決するために行くとき、Blorpleのクラスは、最初に行くを取得、今後、FrobCo.MyExtensionNamespaceのクラス、そしてクラスを

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

をそして:あなたは彼らの上にあなたの優先順位を設定したい場合は、これを行うために選択することができますFrobCoで、そして次にBazCo.TheirExtensionNamespaceのクラス。

これは明確ですか?

+0

ここで1つの質問、どうすればよいですか?私のクラスのために作成された拡張メソッドの上に私のクラスメソッドを隠す?例えばクラスDeerがRunメソッドを持っていて、Deerを "Mars"名前空間(クラスMarsLand)の内部で使用していることを確認したい場合は、Mars名前空間の拡張メソッドで宣言されたRunメソッドが呼び出されるようにします。 Deerは名前空間の一部です。 – Dhananjay

+3

@Dhananjay:クラス階層の中から適用可能なメソッドは、常に*拡張メソッドを優先します。拡張メソッドを呼び出す必要がある場合は、静的メソッドとして呼び出します。 –

+1

'FrobCo.MyExtensionNamespace' *が' BrobCo.TheirExtensionNamespace'より 'FrobCo.Blorble'のどのクラスにも近くないのはなぜですか? BazCo拡張の場合、2つの名前空間レベルを上げ、次に2つの名前空間レベルを上げる必要があると思われますが、FrobCo拡張では1つの名前空間レベルまで上げるだけです。したがって、私にとって、FrobCo拡張はより近くに見えます。 – Virtlink

26

拡張メソッドはインスタンスメソッドではなく、仮想ではないため、上書きできません。

それが呼び出すためにどの方法を知ることができませんとして名前空間を経由して、両方の拡張メソッドのクラスをインポートする場合、コンパイラは文句を言うだろう:

呼び出しは次のメソッドやプロパティの間であいまいです:...

これを回避する唯一の方法は、通常の静的メソッド構文を使用して拡張メソッドを呼び出すことです。だからではなく、この:私はあなたがそれらを無効にすることができますかわからないので、

YourExtensionMethodClass.Foo(a); 
+0

エリックは、それが二つの異なるマッチングの拡張メソッドをインポートしないのメモとして、それは、ネストの同じレベルにそれらをインポートしています。 と、彼は1の動作をオーバーライド話してイムは確かメソッドは、多態性の振る舞いではなく、異なる振る舞いを持ちます –

4

拡張メソッドは、基本的には静的メソッドですが、あなただけ置く場合:

a.Foo(); 

あなたがこれを行う必要がありますそれらを別の名前空間に入れておけば、置き換えたいものの代わりにあなたのものを呼び出すことができます。

しかし、インスタンスメソッドが拡張メソッドに優先します方法についてのマットManelaの話:あなたはhttp://gen5.info/q/2008/07/03/extension-methods-nulls-namespaces-and-precedence-in-c/

編集を見ることができます拡張メソッドについてのより多くのアイデアについては http://social.msdn.microsoft.com/forums/en-US/csharplanguage/thread/e42f1511-39e7-4fed-9e56-0cc19c00d33d

:私はあなたのように、曖昧さの問題について忘れてしまいました最良の方法は、置き換えたい拡張メソッドを含まないようにすることです。したがって、 'using'ディレクティブを使用せずに、いくつかのクラスのパッケージ名全体を入れるだけで問題を解決できるかもしれません。

3

エリックの前提(とビューのコードは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」にする必要があります。

関連する問題