Frage

Warum sind statische Indexer in C # nicht zulässig? Ich sehe keinen Grund, warum sie nicht zugelassen werden, und darüber hinaus können sie sehr nützlich sein.

Zum Beispiel:

public static class ConfigurationManager 
{
        public object this[string name]
        {
            get => ConfigurationManager.getProperty(name);
            set => ConfigurationManager.editProperty(name, value);
        }

        /// <summary>
        /// This will write the value to the property. Will overwrite if the property is already there
        /// </summary>
        /// <param name="name">Name of the property</param>
        /// <param name="value">Value to be wrote (calls ToString)</param>
        public static void editProperty(string name, object value) 
        {
            var ds = new DataSet();
            var configFile = new FileStream("./config.xml", FileMode.OpenOrCreate);
            ds.ReadXml(configFile);

            if (ds.Tables["config"] == null)
                ds.Tables.Add("config");

            var config = ds.Tables["config"];

            if (config.Rows[0] == null) 
                config.Rows.Add(config.NewRow());

            if (config.Columns[name] == null) 
                config.Columns.Add(name);

            config.Rows[0][name] = value.ToString();

            ds.WriteXml(configFile);
            configFile.Close();
        }

        public static void addProperty(string name, object value) =>
            ConfigurationManager.editProperty(name, value);

        public static object getProperty(string name) 
        {
            var ds = new DataSet();
            var configFile = new FileStream("./config.xml", FileMode.OpenOrCreate);
            ds.ReadXml(configFile);
            configFile.Close();

            if (ds.Tables["config"] == null) return null;

            var config = ds.Tables["config"];

            if (config.Rows[0] == null) return null;
            if (config.Columns[name] == null) return null;

            return config.Rows[0][name];
        }
    }

Der obige Code würde stark von einer statischen Indexer profitieren. Allerdings wird es nicht kompiliert, da statische Indexer nicht erlaubt. Warum ist das so?

War es hilfreich?

Lösung

Indexer Notation erfordert einen Verweis auf this. Da statische Methoden keine Bezugnahme auf eine bestimmte Instanz der Klasse haben, können Sie nicht mit ihnen verwenden this, und folglich kann man nicht Indexer Notation auf statische Methoden verwenden.

Die Lösung für Ihr Problem eines Singletonmuster wird wie folgt verwendet:

public class Utilities
{
    private static ConfigurationManager _configurationManager = new ConfigurationManager();
    public static ConfigurationManager ConfigurationManager => _configurationManager;
}
public class ConfigurationManager
{
    public object this[string value]
    {
        get => new object();
        set => // set something
    }
}

Jetzt können Sie Utilities.ConfigurationManager["someKey"] mit Indexer Notation nennen.

Andere Tipps

Ich glaube, es galt nicht besonders nützlich zu sein. Ich denke, es ist eine Schande zu - ein Beispiel, das ich zu verwenden, sind in der Regel ist Encoding, wo Encoding.GetEncoding("foo") Encoding["Foo"] werden konnte. Ich glaube nicht, es kommen würde, sehr oft, aber abgesehen von allem anderen es fühlt sich nur ein wenig inkonsistent nicht zur Verfügung stehen.

Ich würde überprüfen müssen, aber ich verdächtigen es verfügbar ist bereits in IL (Intermediate Language).

Als Behelfslösung können Sie eine Instanz Indexer auf einem Singleton / statisches Objekt definieren (sagen, dass Konfigurationsmanager ist ein Singleton, anstatt eine statische Klasse zu sein):

class ConfigurationManager
{
  //private constructor
  ConfigurationManager() {}
  //singleton instance
  public static ConfigurationManager singleton;
  //indexer
  object this[string name] { ... etc ... }
}

Bei den neueren Konstrukte in C # 6, könnten Sie die Singletonmuster mit einer Eigenschaft Ausdruck Körper vereinfachen. Zum Beispiel habe ich die folgende Verknüpfung, die schön mit Code-Linse funktioniert:

public static class Config
{
   public static NameValueCollection Get => ConfigurationManager.AppSettings;
}

Es hat den zusätzlichen Vorteil, dass find-replace-Lage für älteren Code aktualisieren und Ihre Anwendungseinstellungen Zugang zu vereinen.

Ich war auch in Not (na ja, eher wie nice-to-have) ein statischen Indexer Attribute zu speichern, so dass ich dachte eine etwas peinliche Abhilfe aus:

Innerhalb der Klasse Sie eine statische Indexer haben wollen (hier: Element), eine Unterklasse mit dem gleichen Namen erstellen + „Dict“. Geben Sie ihm einen Nur-Lese-statische als Instanz der Unterklasse, und fügen Sie dann die gewünschte Indexer.

Zuletzt, fügen Sie die Klasse als statische Import (daher der Unterklasse nur das statische Feld aussetzen).

import static Element.ElementDict;

public class Element {
    // .... 
    private static readonly Dictionary<string, object> elemDict = new Dictionary<string, object>();
    public class ElementDict {
        public readonly static ElementDict element = new ElementDict();
        public object this[string key] {
            get => elemDict.TryGetValue(key, out object o) ? o : null;
            set => elemDict[key] = value;
        }
    }
}

und dann können Sie es entweder als Typ aktiviert oder ohne als Wörterbuch:

var cnt = element["counter"] as int;
element["counter"] = cnt;

Aber ach, wenn man tatsächlich ist Objekt zu verwenden, als „Wert“ -Art, dann würde die unten sein noch kürzer (zumindest als Erklärung) und auch sofort liefern Typecasting:

public static T load<T>(string key) => elemDict.TryGetValue(key, out object o) ? (T) o : default(T);
public static void store<T>(string key, T value) => elemDict[key] = value;

var cnt = Element.load<int>("counter");
Element.store("counter", cnt);

Das Schlüsselwort this bezieht sich auf die aktuelle Instanz der Klasse. Statische Member-Funktionen haben keinen diesen Zeiger. Das Schlüsselwort this kann aus Konstrukteuren, Instanzmethoden und Instanz Accessoren für den Zugriff Mitglieder verwendet werden. (Abgerufen von Msdn ). Da es sich um eine Instanz der Klasse verweist es mit der Art der statischen Konflikte, da statisch nicht mit einer Instanz der Klasse zugeordnet ist.

Eine Abhilfe wäre die folgende sein, die Sie den Indexer gegen einen privaten verwenden können Wörterbuch so brauchen Sie nur eine neue Instanz zu erstellen und Sie Zugriff auf den statischen Teil.

    public class ConfigurationManager 
{
    public ConfigurationManager()
    {
        // TODO: Complete member initialization
    }
    public object this[string keyName]
    {
        get
        {
                return ConfigurationManagerItems[keyName];
        }
        set
        {
                ConfigurationManagerItems[keyName] = value;
        }
    }
    private static Dictionary<string, object> ConfigurationManagerItems = new Dictionary<string, object>();        
}

Auf diese Weise können Sie den gesamten Zugriff auf ein Mitglied der Klasse überspringen und nur eine Instanz davon und indizieren erstellen.

    new ConfigurationManager()["ItemName"]

Der Grund dafür ist, weil es sehr schwierig ist, zu verstehen, was genau Sie mit einer statischen Indexer indizieren.

Sie sagen, dass der Code von einem statischen Indexer profitieren würde, aber würde es wirklich? Alles, was es tun würde, dies ändern:

ConfigurationManager.editProperty(name, value);
...
value = ConfigurationManager.getProperty(name)

In diesen:

ConfigurationManager[name] = value
...
value = ConfigurationManager[name]

, die den Code nicht besser in irgendeiner Weise macht; es durch viele Zeilen Code nicht kleiner ist, ist es nicht einfacher, dank schreiben automatisch zu vervollständigen und es ist weniger klar, da es die Tatsache versteckt, dass Sie bekommen und etwas Einstellung ‚Eigentum‘ nennen und es zwingt tatsächlich den Leser gehen lesen Sie die Dokumentation auf, was genau die Indexer zurückkehrt oder satzweise, weil es in keiner Weise ist offensichtlich, dass es eine Eigenschaft ist, dass Sie die Indizierung für, während mit den beiden:

ConfigurationManager.editProperty(name, value);
...
value = ConfigurationManager.getProperty(name)

Sie können es laut vorgelesen und sofort verstehen, was der Code tut.

Beachten Sie, dass wir Code schreiben wollen, das einfach (= schnell) zu verstehen ist, nicht-Code, der schnell zu schreiben ist. Sie nicht die Geschwindigkeit verwechseln, bei dem Sie den Code mit der Geschwindigkeit festgelegt werden kann, an dem Sie komplette Projekte.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top