2008-12-30 4 views
91

Warum sind statische Indexer in C# nicht zulässig? Ich sehe keinen Grund, warum sie nicht erlaubt sein sollten und außerdem könnten sie sehr nützlich sein.Statische Indexer?

Zum Beispiel:

static class ConfigurationManager { 

     public object this[string name]{ 
      get{ 
       return 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) { 
      DataSet ds = new DataSet(); 
      FileStream configFile = new FileStream("./config.xml", FileMode.OpenOrCreate); 
      ds.ReadXml(configFile); 

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

      DataTable 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) { 
      DataSet ds = new DataSet(); 
      FileStream configFile = new FileStream("./config.xml", FileMode.OpenOrCreate); 
      ds.ReadXml(configFile); 
      configFile.Close(); 


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

      DataTable 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. Es wird jedoch nicht kompiliert, da statische Indexer nicht erlaubt sind. Warum ist das so?

+0

Nächste Ich möchte direkte IEnumerable-Implementierung auf statische Klasse, so kann ich tun 'foreach (var enum in Enum)' :) – nawfal

Antwort

55

Indexer Notation erfordert einen Verweis zu this. Da statische Methoden keinen Verweis auf eine bestimmte Instanz der Klasse haben, können Sie this nicht mit ihnen verwenden, und folglich können Sie die Indexer-Notation für statische Methoden nicht verwenden.

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

Sie

    public class Utilities 
    { 
     static ConfigurationManager _configurationManager = new ConfigurationManager(); 
     public static ConfigurationManager ConfigurationManager 
     { 
      get 
      { 
       return _configurationManager; 
      } 
     } 
    } 

    public class ConfigurationManager 
    { 
     public object this[string value] 
     { 
      get 
      { 
       return new object(); 
      } 
      set 
      { 
       // set something 
      } 
     } 
    } 

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

+90

Aber warum muss der Indexer 'this' verwenden? Es muss nicht auf Instanzdaten – Malfist

+68

+1 für Malfists Kommentar zugreifen. Nur weil "this" für einen Instanz-Indexer verwendet wird, bedeutet das nicht, dass sie keine andere Syntax entwickeln können. –

+30

Einverstanden. Du bettelst die Frage an. Du hast im Grunde gesagt, dass es nicht erlaubt ist, weil es nicht erlaubt ist. -1 weil die Frage war: "Warum ist es nicht erlaubt?" – xr280xr

5

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

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

Ah, danke, ich hatte nicht daran gedacht! – Malfist

76

Ich glaube, es wurde als nicht sehr nützlich angesehen. Ich denke, es ist auch eine Schande - ein Beispiel, das ich verwende, ist Encoding, wobei Encoding.GetEncoding ("foo") Encoding ["Foo"] sein könnte. Ich denke nicht, dass es sehr oft kommen würde, aber abgesehen von allem anderen fühlt es sich nur ein wenig inkonsequent an, nicht verfügbar zu sein.

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

+5

Intermediate Language - eine Art Assembler für .NET. –

+10

Was mich hierher gebracht hat, ist, dass ich eine benutzerdefinierte Klasse habe, die ein Wörterbuch mit gemeinsamen Werten in meiner Anwendung über eine statische Eigenschaft verfügbar macht. Ich hoffte, einen statischen Indexer zu verwenden, um den Zugriff von GlobalState.State [KeyName] auf nur GlobalState [KeyName] zu verkürzen. Wäre schön gewesen. – xr280xr

+1

FWIW, das Ändern von "instance" in "static" in der IL für eine Eigenschaft und eine Getter-Methode für eine Standardeigenschaft führt dazu, dass ilasm sich über 'Syntaxfehler beim Token 'statisch' beschweren muss; Ich bin nicht großartig darin, mich in die Angelegenheiten von IL einzumischen, aber das klingt zumindest nach einem anfänglichen Nein. – Amazingant

-2

Das Schlüsselwort this verweist auf die aktuelle Instanz der Klasse. Statische Memberfunktionen haben keinen this-Zeiger. Das this-Schlüsselwort kann verwendet werden, um auf Member innerhalb von Konstruktoren, Instanzmethoden und Instanzenaccessoren zuzugreifen (abgerufen von msdn). Da dies eine Instanz der Klasse referenziert, widerspricht sie der Natur von static, da static keiner Instanz der Klasse zugeordnet ist.

Eine der folgenden Lösungen ermöglicht es Ihnen, den Indexer für ein privates -Wörterbuch zu verwenden, sodass Sie nur eine neue Instanz erstellen müssen und auf den statischen Teil zugreifen müssen.

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>();   
} 

Dies ermöglicht Ihnen, das Ganze zu überspringen ein Mitglied der Klasse zugreifen und nur eine Instanz davon und indiziert erstellen.

new ConfigurationManager()["ItemName"] 
+2

ist ein interessanter Workaround, aber 1) es führt zu Nebeneffekten (Erstellung eines leeren Instanzobjekts), die in einigen Umgebungen zu Speicherdruck und Fragmentierung führen können, 2) die zusätzlichen Zeichen, die von 'new()' verschwendet werden für den Qualifier-Namen eines Singletons stattdessen, wie '.Current' –

+1

Genau wie [Juliets Antwort] (http://stackoverflow.com/a/401275/1430156) beantwortet dies nicht die Frage, warum statische Indexer nicht unterstützt werden. Erstens beschränkt die Frage den Begriff "statischer Indexer" nicht auf "etwas, das das Schlüsselwort' this "verwendet, und zweitens ist' this' in der Syntax 'public string this [int index]' strenggenommen nicht einmal eine Verwendung eines 'this'-Zeigers (wie es im Körper der Instanzmethoden vorkommen kann), aber nur eine andere Verwendung des * token *' this'.Die Syntax 'public static string this [int index]' könnte * ein wenig kontraintuitiv * aussehen, wäre aber dennoch eindeutig. –

+1

@ O.R.Mapper Es könnte auch 'public static string class [int index]' sein. –

-1

Der Grund ist, weil es ziemlich schwer zu verstehen ist, was genau Sie mit einem statischen Indexer indexieren.

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

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

In diese:

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

, die in keiner Weise den Code besser machen; es ist nicht um viele Zeilen Code kleiner, es ist nicht einfacher zu schreiben dank Autocomplete und es ist weniger klar, wie es die Tatsache versteckt, dass Sie etwas bekommen und setzen Sie nennen 'Eigenschaft' und es zwingt tatsächlich den Leser zu 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 beide mit:

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

Sie es lesen kann laut und sofort aus verstehe, was der Code tut.

Denken Sie daran, dass wir Code schreiben möchten, der einfach (= schnell) zu verstehen ist, nicht Code, der schnell zu schreiben ist. Verwechseln Sie nicht die Geschwindigkeit, mit der Sie den Code mit der Geschwindigkeit festlegen können, mit der Sie Projekte abschließen.

+0

Nicht einverstanden. Das ist nur ein konzeptioneller Punkt. Und der Code sieht meiner Meinung nach besser aus, obwohl das nur meine Meinung ist. – ouflak