Frage

Ich bin ein Fan von Erweiterungsmethoden in C #, haben aber keinen Erfolg hatte eine Erweiterungsmethode zu einer statischen Klasse hinzufügen, wie Konsole.

Zum Beispiel, wenn ich will eine Erweiterung Konsole, die so genannte ‚WriteBlueLine‘, hinzufügen, so dass ich gehen kann:

Console.WriteBlueLine("This text is blue");

Ich habe versucht, dies durch eine lokale, öffentliche statische Methode hinzufügen, mit Konsole als ‚diesen‘ Parameter ... 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();
    }
}

Das ist nicht eine ‚WriteBlueLine‘ Methode zur Konsole hinzufügen ... bin ich etwas falsch gemacht? Oder fragt nach dem Unmöglichen?

War es hilfreich?

Lösung

Nein. Erweiterungsmethoden erfordern eine Instanzvariable (Wert) für ein Objekt. Sie können jedoch eine statische Wrapper um die ConfigurationManager Schnittstelle schreiben. Wenn Sie den Wrapper implementieren, müssen Sie nicht eine Erweiterungsmethode benötigen, da Sie nur die Methode direkt hinzufügen können.

 public static class ConfigurationManagerWrapper
 {
      public static ConfigurationSection GetSection( string name )
      {
         return ConfigurationManager.GetSection( name );
      }

      .....

      public static ConfigurationSection GetWidgetSection()
      {
          return GetSection( "widgets" );
      }
 }

Andere Tipps

Können Sie statische Erweiterungen Klassen in C # hinzufügen? Nein, aber Sie können dies tun:

public static class Extensions
{
    public static T Create<T>(this T @this)
        where T : class, new()
    {
        return Utility<T>.Create();
    }
}

public static class Utility<T>
    where T : class, new()
{
    static Utility()
    {
        Create = Expression.Lambda<Func<T>>(Expression.New(typeof(T).GetConstructor(Type.EmptyTypes))).Compile();
    }
    public static Func<T> Create { get; private set; }
}

Hier ist, wie es funktioniert. Während Sie nicht technisch statische Erweiterungsmethoden schreiben, stattdessen nutzt dieser Code eine Lücke in Erweiterungsmethoden. Das Schlupfloch ist, dass Sie Erweiterungsmethoden auf null Objekte, ohne sich die Null Ausnahme nennen kann (es sei denn, Sie etwas über @this zugreifen).

Also hier ist, wie Sie diese nutzen würden:

    var ds1 = (null as DataSet).Create(); // as oppose to DataSet.Create()
    // or
    DataSet ds2 = null;
    ds2 = ds2.Create();

    // using some of the techniques above you could have this:
    (null as Console).WriteBlueLine(...); // as oppose to Console.WriteBlueLine(...)

Nun, warum habe ich wähle Sie den Standard-Konstruktor als Beispiel nennen, und, und warum ich wieder nicht nur neue T () in dem ersten Code-Schnipsel, ohne all der Expression Mülls zu tun? Nun heute Ihr Glückstag, weil Sie erhalten einen 2fer. Wie jeder erweiterte .NET-Entwickler weiß, ist es, neue T () langsam, weil es einen Aufruf an System.Activator erzeugt, die Reflexion des Standardkonstruktors erhalten verwendet, bevor sie anrufen. Verdammt Sie Microsoft! Allerdings meinen Code ruft den Standardkonstruktor des Objekts direkt.

Statische Erweiterungen wären besser als diese aber verzweifelte Zeiten erfordern verzweifelte Maßnahmen.

Es ist nicht möglich.

Und ja ich denke, MS einen Fehler gemacht hier.

Ihre Entscheidung Sinn und Kräfte nicht Programmierer zu schreiben (wie oben beschrieben), um eine sinnlose Wrapper-Klasse.

Hier ist ein gutes Beispiel: Der Versuch, die statische Prüfung Klasse MS Einheit Assert zu erweitern: Ich möchte 1 weitere Methode Assert AreEqual(x1,x2).

Der einzige Weg, dies zu tun ist, um verschiedene Klassen-zu-Punkt oder einen Wrapper um 100s von verschiedenen Assert Methoden schreiben. Warum!?

Wenn die Entscheidung wurde getroffen worden Erweiterungen von Instanzen zu ermöglichen ich keinen logischen Grund sehe keine statischen Erweiterungen zu ermöglichen. Die Argumente über sectioning Bibliotheken nicht stand einmal Instanzen erweitert werden kann.

stieß ich auf diesem Thread nach oben bei dem Versuch, die OP hatte eine Antwort auf die gleiche Frage zu finden. Ich fand nicht die Antwort, die ich wollte, aber ich endete dies zu tun.

public static class MyConsole
{
    public static void WriteLine(this ConsoleColor Color, string Text)
    {
        Console.ForegroundColor = Color;
        Console.WriteLine(Text);   
    }
}

Und ich benutze es wie folgt aus:

ConsoleColor.Cyan.WriteLine("voilà");

Vielleicht könnten Sie eine statische Klasse mit Ihrem eigenen Namensraum und den gleichen Klasse Namen:

using CLRConsole = System.Console;

namespace ExtensionMethodsDemo
{
    public static class Console
    {
        public static void WriteLine(string value)
        {
            CLRConsole.WriteLine(value);
        }

        public static void WriteBlueLine(string value)
        {
            System.ConsoleColor currentColor = CLRConsole.ForegroundColor;

            CLRConsole.ForegroundColor = System.ConsoleColor.Blue;
            CLRConsole.WriteLine(value);

            CLRConsole.ForegroundColor = currentColor;
        }

        public static System.ConsoleKeyInfo ReadKey(bool intercept)
        {
            return CLRConsole.ReadKey(intercept);
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            try
            {
                Console.WriteBlueLine("This text is blue");   
            }
            catch (System.Exception ex)
            {
                Console.WriteLine(ex.Message);
                Console.WriteLine(ex.StackTrace);
            }

            Console.WriteLine("Press any key to continue...");
            Console.ReadKey(true);
        }
    }
}

Nein. Erweiterung Methodendefinitionen erfordern eine Instanz des Typs Sie erstrecken. Es ist unglücklich; Ich bin mir nicht sicher, warum seine erforderlich ...

Wie von C # 7 dies wird nicht unterstützt. Es gibt jedoch Diskussionen über etwas zu integrieren wie das in C # 8 und Vorschläge unterstützenswert .

Wie für Erweiterungsmethoden, Erweiterungsmethoden selbst sind statisch; aber sie sind aufgerufen, als ob sie Instanzmethoden sind. Da eine statische Klasse nicht instantiable ist, würden Sie nie eine Instanz der Klasse von eine Erweiterungsmethode aufzurufen. Aus diesem Grunde der Compiler erlaubt keine Erweiterungsmethoden für statische Klassen definiert werden.

Mr. Abscheuliche hat geschrieben:. „Wie jeder erweiterte .NET-Entwickler weiß, new T () langsam ist, weil es einen Aufruf an System.Activator die Reflexion verwendet erzeugt, bevor der Standard-Konstruktor zu bekommen nannte es“

Neu () auf die IL „NEWOBJ“ Anweisung kompiliert, wenn der Typ zum Zeitpunkt der Kompilierung bekannt ist. NEWOBJ nimmt einen Konstruktor für den direkten Aufruf. Anrufe zu System.Activator.CreateInstance () kompilieren, um die IL "call" Anweisung System.Activator.CreateInstance aufzurufen (). Neu (), wenn sie gegen generische Typen, die in einem Aufruf von System.Activator.CreateInstance () resultiert. Der Beitrag von Herrn Widerlich war in diesem Punkt unklar ... und gut, abscheulich.

Mit diesem Code:

System.Collections.ArrayList _al = new System.Collections.ArrayList();
System.Collections.ArrayList _al2 = (System.Collections.ArrayList)System.Activator.CreateInstance(typeof(System.Collections.ArrayList));

erzeugt diese IL:

  .locals init ([0] class [mscorlib]System.Collections.ArrayList _al,
           [1] class [mscorlib]System.Collections.ArrayList _al2)
  IL_0001:  newobj     instance void [mscorlib]System.Collections.ArrayList::.ctor()
  IL_0006:  stloc.0
  IL_0007:  ldtoken    [mscorlib]System.Collections.ArrayList
  IL_000c:  call       class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
  IL_0011:  call       object [mscorlib]System.Activator::CreateInstance(class [mscorlib]System.Type)
  IL_0016:  castclass  [mscorlib]System.Collections.ArrayList
  IL_001b:  stloc.1

Sie können nicht hinzufügen statisch Methoden auf einen Typ. Sie können nur hinzufügen (pseudo-) Instanzmethoden auf eine Instanz eines Typs.

Der Punkt des this Modifikator ist der C # Compiler mitzuteilen, die Instanz auf der linken Seite des . als erste Parameter der statischen / Extension-Methode übergeben.

Im Fall des Hinzufügens von statischen Methoden auf einen Typen, gibt es kein Beispiel für den ersten Parameter zu übergeben.

Ich habe versucht, diese wieder mit System.Environment zu tun, wenn ich Erweiterungsmethoden wurde das Lernen und war nicht erfolgreich. Der Grund dafür ist, wie andere erwähnen, weil Erweiterungsmethoden eine Instanz der Klasse benötigen.

ja, in einem begrenzten Sinne.

public class DataSet : System.Data.DataSet
{
    public static void SpecialMethod() { }
}

Das funktioniert aber Console nicht, weil es statisch ist.

public static class Console
{       
    public static void WriteLine(String x)
    { System.Console.WriteLine(x); }

    public static void WriteBlueLine(String x)
    {
        System.Console.ForegroundColor = ConsoleColor.Blue;
        System.Console.Write(.x);           
    }
}

Das funktioniert, weil solange es nicht auf dem gleichen Namensraum ist. Das Problem ist, dass Sie eine Proxy-statische Methode für jede Methode zu schreiben, die System.Console hat. Es ist nicht unbedingt eine schlechte Sache, wie Sie so etwas wie dies hinzufügen:

    public static void WriteLine(String x)
    { System.Console.WriteLine(x.Replace("Fck","****")); }

oder

 public static void WriteLine(String x)
    {
        System.Console.ForegroundColor = ConsoleColor.Blue;
        System.Console.WriteLine(x); 
    }

Das System funktioniert so, dass Sie etwas in den Standard Console.WriteLine Haken. Es könnte eine Zeilenzahl oder Wortfilter oder was auch immer sein. Jedes Mal, wenn Sie nur Konsole in Ihrem Namensraum angeben sagen WebProject1 und das Namespace-System importieren, wird WebProject1.Console für diese Klassen im Namensraum WebProject1 über System.Console als Standard gewählt werden. Also dieser Code wird sich die ganze Console.WriteLine in blau ruft, sofern Sie nie System.Console.WriteLine angegeben.

Im Folgenden wurde als bearbeiten tvanfosson Antwort abgelehnt. Ich wurde gebeten, es als meine eigene Antwort beizutragen. Ich habe seinen Vorschlag und beenden die Implementierung eines ConfigurationManager-Wrapper. Im Prinzip ausgefüllte ich einfach die ... in tvanfosson Antwort.

  

Nein. Erweiterungsmethoden erfordern eine Instanz eines Objekts. Du kannst   jedoch, schreiben Sie eine statische Wrapper um den Konfigurationsmanager   Schnittstelle. Wenn Sie den Wrapper implementieren, benötigen Sie keine Verlängerung   Methode, da Sie die Methode direkt nur hinzufügen können.

public static class ConfigurationManagerWrapper
{
    public static NameValueCollection AppSettings
    {
        get { return ConfigurationManager.AppSettings; }
    }

    public static ConnectionStringSettingsCollection ConnectionStrings
    {
        get { return ConfigurationManager.ConnectionStrings; }
    }

    public static object GetSection(string sectionName)
    {
        return ConfigurationManager.GetSection(sectionName);
    }

    public static Configuration OpenExeConfiguration(string exePath)
    {
        return ConfigurationManager.OpenExeConfiguration(exePath);
    }

    public static Configuration OpenMachineConfiguration()
    {
        return ConfigurationManager.OpenMachineConfiguration();
    }

    public static Configuration OpenMappedExeConfiguration(ExeConfigurationFileMap fileMap, ConfigurationUserLevel userLevel)
    {
        return ConfigurationManager.OpenMappedExeConfiguration(fileMap, userLevel);
    }

    public static Configuration OpenMappedMachineConfiguration(ConfigurationFileMap fileMap)
    {
        return ConfigurationManager.OpenMappedMachineConfiguration(fileMap);
    }

    public static void RefreshSection(string sectionName)
    {
        ConfigurationManager.RefreshSection(sectionName);
    }
}

Es ist nicht möglich, eine Erweiterungsmethode zu schreiben, jedoch ist es möglich, das Verhalten, das Sie fordern.

nachahmen
using FooConsole = System.Console;

public static class Console
{
    public static void WriteBlueLine(string text)
    {
        FooConsole.ForegroundColor = ConsoleColor.Blue;
        FooConsole.WriteLine(text);
        FooConsole.ResetColor();
    }
}

Dies ermöglicht es Ihnen Console.WriteBlueLine (fooText) in anderen Klassen zu nennen. Wenn die anderen Klassen Zugang zu den anderen statischen Funktionen der Konsole wollen, müssen sie explizit durch ihren Namensraum referenziert werden.

Sie können immer alle Methoden in der Ersetzung Klasse hinzufügen, wenn Sie sie alle an einem Ort haben wollen.

Sie würden also so etwas wie haben

using FooConsole = System.Console;

public static class Console
{
    public static void WriteBlueLine(string text)
    {
        FooConsole.ForegroundColor = ConsoleColor.Blue;
        FooConsole.WriteLine(text);
        FooConsole.ResetColor();
    }
    public static void WriteLine(string text)
    {
        FooConsole.WriteLine(text);
    }
...etc.
}

Dies würde die Art von Verhalten bieten Sie suchen.

* Anmerkung Console wird durch den Namensraum haben hinzugefügt, dass Sie es in.

Sie können eine Besetzung auf null verwenden, damit es funktioniert.

public static class YoutTypeExtensionExample
{
    public static void Example()
    {
        ((YourType)null).ExtensionMethod();
    }
}

Die Erweiterung:

public static class YourTypeExtension
{
    public static void ExtensionMethod(this YourType x) { }
}

Yourtype:

public class YourType { }

Sie können dies tun, wenn Sie, indem Sie eine Variable der statischen Klasse bereit, „frig“ es ein wenig sind und die Zuordnung es auf null. Allerdings wäre dieses Verfahren nicht auf statische fordert die Klasse zur Verfügung stehen, so dass nicht sicher, wie viel Einsatz es wäre:

Console myConsole = null;
myConsole.WriteBlueLine("my blue line");

public static class Helpers {
    public static void WriteBlueLine(this Console c, string text)
    {
        Console.ForegroundColor = ConsoleColor.Blue;
        Console.WriteLine(text);
        Console.ResetColor();
    }
}
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top