Ich habe eine Erweiterungsmethode für eine ASP.NET MVC ViewPage erstellt, z.
public static class ViewExtensions
{
public static string Method<T>(this ViewPage<T> page) where T : class
{
return "something";
}
}
Beim Aufrufen dieser Methode aus einer Ansicht (abgeleitet von ViewPage
) wird die Fehlermeldung " CS0103: Der Name 'Methode' ist im aktuellen Kontext nicht vorhanden " angezeigt, es sei denn, ich verwende das this
Schlüsselwort, um sie aufzurufen:
<%: Method() %> <!-- gives error CS0103 -->
<%: this.Method() %> <!-- works -->
Warum ist das this
Schlüsselwort erforderlich? Oder funktioniert es ohne, aber mir fehlt etwas?
(Ich denke, es muss ein Duplikat dieser Frage geben, aber ich konnte keines finden)
Update :
Wie Ben Robinson sagt , ist die Syntax zum Aufrufen von Erweiterungsmethoden nur Compilerzucker. Warum kann der Compiler dann nicht automatisch nach Erweiterungsmethoden der Basistypen des aktuellen Typs suchen, ohne das Schlüsselwort this zu benötigen?
this
Schlüsselwort hinzufügen muss ), sondern ich frage, warum dasthis
Schlüsselwort erforderlich ist. Ich habe meine Frage aktualisiert.Antworten:
Ein paar Punkte:
Zunächst einmal ist die vorgeschlagene Funktion (implizites "this" bei einem Aufruf einer Erweiterungsmethode) nicht erforderlich . Erweiterungsmethoden waren erforderlich, damit das Verständnis von LINQ-Abfragen wie gewünscht funktioniert. Der Empfänger wird immer in der Abfrage angegeben, daher ist es nicht erforderlich, dies implizit zu unterstützen, damit LINQ funktioniert.
Zweitens arbeitet die Funktion gegen den allgemeineren Design von Erweiterungsmethoden: nämlich, dass die Erweiterungsmethoden ermöglichen es Ihnen , eine Art zu erweitern , dass Sie sich nicht erweitern können , sei es, weil es sich um eine Schnittstelle ist , und Sie wissen nicht , die Implementierung, oder weil Sie tun kennen die Implementierung, haben aber nicht den Quellcode.
Wenn Sie in dem Szenario, wo Sie eine Erweiterungsmethode für einen Typ verwenden in dieser Art dann Sie haben Zugriff auf den Quellcode. Warum verwenden Sie dann überhaupt eine Erweiterungsmethode? Sie können selbst eine Instanzmethode schreiben, wenn Sie Zugriff auf den Quellcode des erweiterten Typs haben, und dann müssen Sie überhaupt keine Erweiterungsmethode verwenden! Ihre Implementierung kann dann den Zugriff auf den privaten Status des Objekts nutzen, den Erweiterungsmethoden nicht können.
Wenn Sie die Verwendung von Erweiterungsmethoden innerhalb eines Typs, auf den Sie Zugriff haben, vereinfachen möchten, wird die Verwendung von Erweiterungsmethoden gegenüber Instanzmethoden empfohlen. Erweiterungsmethoden sind großartig, aber es ist normalerweise besser, eine Instanzmethode zu verwenden, wenn Sie eine haben.
Angesichts dieser beiden Punkte muss der Sprachdesigner nicht mehr erklären, warum die Funktion nicht vorhanden ist. Es liegt nun an Ihnen zu erklären, warum es sollte . Features sind mit enormen Kosten verbunden. Diese Funktion ist nicht erforderlich und widerspricht den angegebenen Entwurfszielen von Erweiterungsmethoden. Warum sollten wir die Kosten für die Implementierung übernehmen? Erklären Sie, welches überzeugende, wichtige Szenario durch diese Funktion ermöglicht wird, und wir werden in Betracht ziehen, es in Zukunft zu implementieren. Ich sehe kein zwingendes, wichtiges Szenario, das dies rechtfertigt, aber vielleicht gibt es eines, das ich verpasst habe.
quelle
this
erforderlich ist. 2: Warum rufe ich eine Erweiterungsmethode vom erweiterten Typ auf? In dem angegebenen Beispiel füge ich der Basisklasse (ViewPage) einige praktische Methoden hinzu und rufe sie aus abgeleiteten Klassen auf. Dadurch entfällt die Notwendigkeit, eine gemeinsame Basisklasse für alle meine Ansichten zu erstellen. Übrigens: Ich stimme zu, dass die Verwendung einer Erweiterungsmethode innerhalb des erweiterten Typs umständlich ist, aber siehe auch das Beispiel mit MVC ViewPage.ICrossProductable
, und Sie definieren eine Erweiterungsmethode auf dieser Schnittstelle, die aufgerufen wirdGetProduct
. Sehr einfaches Beispiel, aber ich finde das oft nützlich. Es ist jedoch nicht in allen Fällen der beste Ansatz.Ohne sie sieht der Compiler es nur als statische Methode in einer statischen Klasse, die Seite als ersten Parameter verwendet. dh
// without 'this' string s = ViewExtensions.Method(page);
vs.
// with 'this' string s = page.Method();
quelle
Bei Instanzmethoden wird 'this' implizit transparent an jede Methode übergeben, sodass Sie auf alle von ihr bereitgestellten Mitglieder zugreifen können.
Erweiterungsmethoden sind statisch. Wenn Sie
Method()
stattthis.Method()
oder aufrufenMethod(this)
, teilen Sie dem Compiler nicht mit, was an die Methode übergeben werden soll.Sie könnten sagen: "Warum erkennt es nicht einfach, was das aufrufende Objekt ist, und übergeben es als Parameter?"
Die Antwort ist, dass Erweiterungsmethoden statisch sind und aus einem statischen Kontext aufgerufen werden können, in dem es kein "dies" gibt.
Ich denke, sie könnten das während der Kompilierung überprüfen, aber um ehrlich zu sein, ist es wahrscheinlich eine Menge Arbeit für extrem wenig Gewinn. Und um ehrlich zu sein, sehe ich wenig Nutzen darin, einige der expliziten Aufrufe von Erweiterungsmethoden wegzunehmen. Die Tatsache, dass sie beispielsweise mit Methoden verwechselt werden können, bedeutet, dass sie manchmal ziemlich unintuitiv sind (NullReferenceExceptions werden beispielsweise nicht ausgelöst). Ich denke manchmal, dass sie einen neuen Pipe-Forward-Operator für Erweiterungsmethoden hätten einführen sollen.
quelle
Es ist wichtig zu beachten, dass es Unterschiede zwischen Erweiterungsmethoden und regulären Methoden gibt. Ich denke, Sie sind gerade auf einen von ihnen gestoßen.
Ich gebe Ihnen ein Beispiel für einen weiteren Unterschied: Es ist ziemlich einfach, eine Erweiterungsmethode für eine
null
Objektreferenz aufzurufen . Glücklicherweise ist dies mit regulären Methoden viel schwieriger zu tun. (Aber es kann getan werden. IIRC, Jon Skeet demonstrierte, wie dies durch Manipulieren des CIL-Codes zu tun ist.)static void ExtensionMethod(this object obj) { ... } object nullObj = null; nullObj.ExtensionMethod(); // will succeed without a NullReferenceException!
Trotzdem stimme ich zu, dass es ein wenig unlogisch erscheint,
this
die Erweiterungsmethode aufzurufen. Schließlich sollte sich eine Erweiterungsmethode idealerweise wie eine normale Methode "fühlen" und verhalten.In Wirklichkeit ähneln Erweiterungsmethoden jedoch eher syntaktischem Zucker, der zusätzlich zur vorhandenen Sprache hinzugefügt wird, als einem frühen Kernmerkmal, das in jeder Hinsicht gut in die Sprache passt.
quelle
null
? Könnte fast jeder Referenztyp sein, woher weiß es, auf welchen Methoden es verfügbar istnull
?String
logisch verhalten sich wie Werte und können einen sinnvollen Standardwert haben, wenn null (z. B. .net kann eine Nullreferenz vom statischen Typ konsistentstring
als leere Zeichenfolge betrachten, anstatt dies nur sporadisch zu tun). Statische Methoden für Dinge wie verwenden zu müssen,if (!String.IsNullOrEmpty(stringVar))
ist einfach abscheulich.Weil die Erweiterungsmethode mit der ViewPage-Klasse nicht vorhanden ist. Sie müssen dem Compiler mitteilen, für was Sie die Erweiterungsmethode aufrufen. Denken Sie daran,
this.Method()
ist nur Compiler Zucker fürViewExtensions.Method(this)
. Auf die gleiche Weise können Sie eine Erweiterungsmethode nicht einfach in der Mitte einer Klasse mit dem Methodennamen aufrufen.quelle
this
Schlüsselwort nach Erweiterungsmethoden suchen?Ich arbeite an einer fließenden API und bin auf dasselbe Problem gestoßen. Obwohl ich Zugriff auf die Klasse habe, die ich erweitere, wollte ich, dass die Logik jeder der fließenden Methoden in ihren eigenen Dateien enthalten ist. Das Schlüsselwort "this" war sehr unintuitiv. Die Benutzer dachten immer wieder, dass die Methode fehlte. Ich habe meine Klasse zu einer Teilklasse gemacht, die die benötigten Methoden implementiert hat, anstatt Erweiterungsmethoden zu verwenden. Ich sah keine Erwähnung von Teiltönen in den Antworten. Wenn Sie diese Frage haben, sind Teiltöne möglicherweise die bessere Option.
quelle