Come sovrascrivere un metodo di estensione esistente

Voglio sostituire i metodi di estensione inclusi nel framework .NET o ASP MVC con i miei metodi.

Esempio

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

È ansible? Non riesco a usare la parola chiave override o nuova.

AGGIORNAMENTO: questa domanda è stata object del mio blog nel dicembre del 2013 . Grazie per la bella domanda!


Puoi farlo, in un certo senso. Ma dovrei iniziare parlando brevemente del principio di base della risoluzione di sovraccarico in C #. Tutta la risoluzione di sovraccarico è, ovviamente, sul prendere un insieme di metodi con lo stesso nome e scegliere da quel set il membro migliore da chiamare.

Ci sono molti fattori coinvolti nel determinare qual è il metodo “migliore”; lingue diverse usano una diversa “miscela” di fattori per capirlo. In particolare, C # appesantisce pesantemente la “vicinanza” di un determinato metodo al sito di chiamata. Se viene data la scelta tra un metodo applicabile in una class base o un nuovo metodo applicabile in una class derivata, C # prende quello nella class derivata perché è più vicino, anche se quello nella class base è in ogni altro modo un migliore incontro.

E così scendiamo la lista. Le classi derivate sono più vicine delle classi base. Le classi interne sono più vicine delle classi esterne. I metodi nella gerarchia delle classi sono più vicini dei metodi di estensione.

E ora veniamo alla tua domanda. La vicinanza di un metodo di estensione dipende da (1) quanti spazi dei nomi “fuori” dovevamo andare? e (2) abbiamo trovato il metodo di estensione using o era proprio lì nello spazio dei nomi? Pertanto, è ansible influenzare la risoluzione di sovraccarico modificando in quale spazio dei nomi viene visualizzata la class di estensione statica, per inserirlo in uno spazio dei nomi più vicino al sito di chiamata. Oppure, puoi cambiare le tue dichiarazioni using , per mettere l’ using dello spazio dei nomi che contiene la class statica desiderata più vicina dell’altra.

Ad esempio, se lo hai

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

allora è ambiguo che è più vicino. Se vuoi dare la priorità al tuo, puoi scegliere di farlo:

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

E ora, quando la risoluzione del sovraccarico va a risolvere la chiamata del metodo di estensione, le classi in Blorple vanno prima, quindi le classi in FrobCo.MyExtensionNamespace , quindi le classi in FrobCo e quindi le classi in BazCo.TheirExtensionNamespace .

È chiaro?

I metodi di estensione non possono essere sovrascritti poiché non sono metodi di istanza e non sono virtuali.

Il compilatore si lamenterà se si importano entrambe le classi del metodo di estensione tramite namespace in quanto non conoscono il metodo da chiamare:

La chiamata è ambigua tra i seguenti metodi o proprietà: …

L’unico modo per aggirare questo è chiamare il metodo di estensione usando la normale syntax del metodo statico. Quindi, invece di questo:

 a.Foo(); 

dovresti fare questo:

 YourExtensionMethodClass.Foo(a); 

I metodi di estensione sono fondamentalmente solo metodi statici quindi non so come sia ansible sovrascriverli, ma se li si inserisce in uno spazio dei nomi diverso, è ansible chiamare il proprio anziché quello che si desidera sostituire.

Ma Matt Manela parla di come i metodi di istanza abbiano la precedenza sui metodi di estensione: http://social.msdn.microsoft.com/forums/en-US/csharplanguage/thread/e42f1511-39e7-4fed-9e56-0cc19c00d33d

Per ulteriori idee sui metodi di estensione puoi consultare http://gen5.info/q/2008/07/03/extension-methods-nulls-namespaces-and-precedence-in-c/

Modifica: ho dimenticato il problema dell’ambiguità, quindi la soluzione migliore è provare a non includere i metodi di estensione che desideri sostituire. Quindi, potrebbe non essere necessario usare la direttiva ‘using’ ma inserire semplicemente l’intero nome del pacchetto di alcune classi, e questo potrebbe risolvere il problema.

Basato sulla premessa di Eric (e il fatto che il codice delle viste sia reso nello spazio dei nomi ASP) dovresti riuscire a sovrascriverlo in questo modo (almeno funziona per me in 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)); } } } 

Nota che lo spazio dei nomi deve essere “ASP”.

Oltre alle risposte esistenti, puoi anche “sovrascrivere” i metodi di estensione alterando la firma del metodo:

1.) Usa un tipo più specifico

Questo può essere utilizzato solo se il tipo di destinazione è più specifico di quello del metodo di estensione esistente. Inoltre, potrebbe essere necessario farlo per tutti i tipi applicabili.

 // "override" the default Linq method by using a more specific type public static bool Any(this List source) { return Enumerable.Any(source); } // this will call YOUR extension method new List().Any(); 

2.) Aggiungi un parametro fittizio

Non così carino. Inoltre, questo richiederà di modificare le chiamate esistenti per includere l’argomento dummy.

 // this will be called instead of the default Linq method when "override" is specified public static bool Any(this IEnumerable source, bool @override = true) { return source.Any(); } // this will call YOUR extension method new List().Any(true);