Ich bin ein Fan von Erweiterungsmethoden in C #, hatte aber keinen Erfolg beim Hinzufügen einer Erweiterungsmethode zu einer statischen Klasse wie Console.
Wenn ich beispielsweise der Konsole eine Erweiterung mit dem Namen 'WriteBlueLine' hinzufügen möchte, damit ich gehen kann:
Console.WriteBlueLine("This text is blue");
Ich habe dies versucht, indem ich eine lokale, öffentliche statische Methode mit Console als 'this'-Parameter hinzugefügt habe ... aber keine Würfel!
public static class Helpers {
public static void WriteBlueLine(this Console c, string text)
{
Console.ForegroundColor = ConsoleColor.Blue;
Console.WriteLine(text);
Console.ResetColor();
}
}
Dies hat der Konsole keine 'WriteBlueLine'-Methode hinzugefügt ... mache ich das falsch? Oder nach dem Unmöglichen fragen?
c#
static
extension-methods
Leon Bambrick
quelle
quelle
Helpers.WriteBlueLine(null, "Hi");
:)Antworten:
Nein. Erweiterungsmethoden erfordern eine Instanzvariable (Wert) für ein Objekt. Sie können jedoch einen statischen Wrapper um die
ConfigurationManager
Schnittstelle schreiben . Wenn Sie den Wrapper implementieren, benötigen Sie keine Erweiterungsmethode, da Sie die Methode einfach direkt hinzufügen können.quelle
Können Sie Klassen in C # statische Erweiterungen hinzufügen? Nein, aber Sie können dies tun:
So funktioniert das. Obwohl Sie technisch keine statischen Erweiterungsmethoden schreiben können, nutzt dieser Code eine Lücke in den Erweiterungsmethoden. Diese Lücke besteht darin, dass Sie Erweiterungsmethoden für Nullobjekte aufrufen können, ohne die Nullausnahme zu erhalten (es sei denn, Sie greifen über @this auf etwas zu).
So würden Sie dies verwenden:
WARUM habe ich den Standardkonstruktor als Beispiel aufgerufen und UND warum gebe ich nicht einfach neues T () im ersten Codeausschnitt zurück, ohne den gesamten Ausdrucksmüll zu verursachen? Nun, heute ist dein Glückstag, denn du bekommst einen 2fer. Wie jeder fortgeschrittene .NET-Entwickler weiß, ist new T () langsam, da es einen Aufruf von System.Activator generiert, der Reflection verwendet, um den Standardkonstruktor vor dem Aufruf abzurufen. Verdammt Microsoft! Mein Code ruft jedoch den Standardkonstruktor des Objekts direkt auf.
Statische Erweiterungen wären besser als diese, aber verzweifelte Zeiten erfordern verzweifelte Maßnahmen.
quelle
XConsole
,ConsoleHelper
und so weiter.(null as DataSet).Create();
könnte seindefault(DataSet).Create();
.Es ist nicht möglich.
Und ja, ich denke, MS hat hier einen Fehler gemacht.
Ihre Entscheidung ist nicht sinnvoll und zwingt Programmierer, (wie oben beschrieben) eine sinnlose Wrapper-Klasse zu schreiben.
Hier ein gutes Beispiel: Versuch, die statische MS Unit-Testklasse zu erweitern Assert: Ich möchte 1 weitere Assert-Methode
AreEqual(x1,x2)
.Die einzige Möglichkeit, dies zu tun, besteht darin, auf verschiedene Klassen zu verweisen oder einen Wrapper mit etwa 100 verschiedenen Assert-Methoden zu schreiben. Warum!?
Wenn die Entscheidung getroffen wurde, Erweiterungen von Instanzen zuzulassen, sehe ich keinen logischen Grund, statische Erweiterungen nicht zuzulassen. Die Argumente zum Schneiden von Bibliotheken stehen nicht zur Verfügung, sobald Instanzen erweitert werden können.
quelle
Assert.Throws
mit der Antwort stackoverflow.com/questions/113395/…Ich bin auf diesen Thread gestoßen, als ich versucht habe, eine Antwort auf dieselbe Frage zu finden, die das OP hatte. Ich habe nicht die Antwort gefunden, die ich wollte, aber am Ende habe ich das getan.
Und ich benutze es so:
quelle
Vielleicht könnten Sie eine statische Klasse mit Ihrem benutzerdefinierten Namespace und demselben Klassennamen hinzufügen:
quelle
Ab C # 7 wird dies nicht unterstützt. Es gibt jedoch Diskussionen über die Integration von so etwas in C # 8 und Vorschläge, die es wert sind, unterstützt zu werden .
quelle
Nee. Für Definitionen von Erweiterungsmethoden ist eine Instanz des Typs erforderlich, den Sie erweitern. Es ist unglücklich; Ich bin nicht sicher, warum es erforderlich ist ...
quelle
Bei Erweiterungsmethoden sind die Erweiterungsmethoden selbst statisch. Sie werden jedoch so aufgerufen, als wären sie Instanzmethoden. Da eine statische Klasse nicht instanziierbar ist, hätten Sie niemals eine Instanz der Klasse, von der aus Sie eine Erweiterungsmethode aufrufen könnten. Aus diesem Grund erlaubt der Compiler nicht, Erweiterungsmethoden für statische Klassen zu definieren.
Herr Obnoxious schrieb: "Wie jeder fortgeschrittene .NET-Entwickler weiß, ist new T () langsam, da es einen Aufruf von System.Activator generiert, der Reflection verwendet, um den Standardkonstruktor vor dem Aufruf abzurufen."
New () wird in den IL-Befehl "newobj" kompiliert, wenn der Typ zur Kompilierungszeit bekannt ist. Newobj verwendet einen Konstruktor für den direkten Aufruf. Aufrufe von System.Activator.CreateInstance () werden mit der IL-Anweisung "call" kompiliert, um System.Activator.CreateInstance () aufzurufen. New () führt bei Verwendung für generische Typen zu einem Aufruf von System.Activator.CreateInstance (). Der Beitrag von Mr. Obnoxious war in diesem Punkt unklar ... und nun, widerlich.
Dieser Code:
produziert diese IL:
quelle
Sie können einem Typ keine statischen Methoden hinzufügen . Sie können einer Instanz eines Typs nur (Pseudo-) Instanzmethoden hinzufügen.
Der
this
Modifikator soll den C # -Compiler anweisen, die Instanz auf der linken Seite des zu übergeben.
als ersten Parameter der statischen / Erweiterungsmethode zu übergeben.Beim Hinzufügen statischer Methoden zu einem Typ muss keine Instanz für den ersten Parameter übergeben werden.
quelle
Ich habe versucht, dies mit System.Environment zu tun, als ich Erweiterungsmethoden lernte und nicht erfolgreich war. Der Grund ist, wie andere erwähnen, dass Erweiterungsmethoden eine Instanz der Klasse erfordern.
quelle
Es ist nicht möglich, eine Erweiterungsmethode zu schreiben, es ist jedoch möglich, das gewünschte Verhalten nachzuahmen.
Auf diese Weise können Sie Console.WriteBlueLine (fooText) in anderen Klassen aufrufen. Wenn die anderen Klassen Zugriff auf die anderen statischen Funktionen von Console wünschen, müssen sie über ihren Namespace explizit referenziert werden.
Sie können der Ersetzungsklasse jederzeit alle Methoden hinzufügen, wenn Sie alle an einem Ort haben möchten.
Sie hätten also so etwas wie
Dies würde die Art von Verhalten liefern, nach der Sie suchen.
* Hinweis Die Konsole muss über den Namespace hinzugefügt werden, in den Sie sie eingefügt haben.
quelle
ja, in einem begrenzten Sinne.
Dies funktioniert, die Konsole jedoch nicht, da sie statisch ist.
Dies funktioniert, weil es sich nicht im selben Namespace befindet. Das Problem ist, dass Sie für jede Methode von System.Console eine statische Proxy-Methode schreiben müssen. Es ist nicht unbedingt eine schlechte Sache, da Sie so etwas hinzufügen können:
oder
Die Art und Weise, wie es funktioniert, ist, dass Sie etwas in die Standard-WriteLine einbinden. Es könnte eine Zeilenanzahl oder ein Filter für schlechte Wörter oder was auch immer sein. Wenn Sie in Ihrem Namespace nur "Konsole" angeben, z. B. "WebProject1", und den Namespace "System" importieren, wird "WebProject1.Console" für diese Klassen im Namespace "WebProject1" anstelle von "System.Console" ausgewählt. Dieser Code verwandelt also alle Console.WriteLine-Aufrufe in Blau, sofern Sie System.Console.WriteLine nie angegeben haben.
quelle
Folgendes wurde als abgelehnt bearbeiten zu tvanfosson Antwort. Ich wurde gebeten, es als meine eigene Antwort beizutragen. Ich habe seinen Vorschlag verwendet und die Implementierung eines
ConfigurationManager
Wrappers abgeschlossen. Im Prinzip habe ich einfach...
die Antwort von in tvanfosson ausgefüllt .quelle
Sie können eine Umwandlung in null verwenden, damit es funktioniert.
Die Erweiterung:
Dein Typ:
quelle
Sie können dies tun, wenn Sie bereit sind, es ein wenig zu "friggen", indem Sie eine Variable der statischen Klasse erstellen und sie null zuweisen. Diese Methode ist jedoch für statische Aufrufe der Klasse nicht verfügbar. Sie sind sich also nicht sicher, wie häufig sie verwendet wird:
quelle