2008-12-30 9 views
91

Pourquoi les indexeurs statiques ne sont-ils pas autorisés en C#? Je ne vois aucune raison pour laquelle ils ne devraient pas être autorisés et de plus ils pourraient être très utiles.Indexeurs statiques?

Par exemple:

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]; 
     } 
    } 

Le code ci-dessus bénéficierait grandement d'un indexeur statique. Cependant, il ne compilera pas car les indexeurs statiques ne sont pas autorisés. Pourquoi cela est-il ainsi?

+0

Ensuite, je veux l'implémentation directe IEnumerable sur la classe statique, donc je peux faire 'foreach (var enum enum)' :) – nawfal

Répondre

55

notation Indexer nécessite une référence à this. Puisque les méthodes statiques n'ont pas de référence à une instance particulière de la classe, vous ne pouvez pas utiliser this avec elles, et par conséquent vous ne pouvez pas utiliser la notation d'indexeur sur les méthodes statiques.

La solution à votre problème utilise un singleton comme suit:


    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 
      } 
     } 
    } 

Maintenant, vous pouvez appeler Utilities.ConfigurationManager["someKey"] en utilisant la notation indexeur. Je crois qu'il a été considéré comme n'étant pas terriblement utile.

+90

Mais pourquoi l'indexeur doit-il utiliser 'ceci'? Il n'a pas besoin d'accéder aux données d'instance – Malfist

+68

+1 pour le commentaire de Malfist. Ce n'est pas parce qu'il utilise "ceci" pour un indexeur d'instance qu'il ne peut pas trouver d'autre syntaxe. –

+30

D'accord. Vous suppliez la question. Vous avez essentiellement dit que la raison pour laquelle ce n'est pas permis est parce que ce n'est pas autorisé. -1 parce que la question était "pourquoi est-ce interdit?" – xr280xr

5

En tant que travail autour, vous pouvez définir un indexeur d'instance sur un objet singleton/statique (disons que ConfigurationManager est un singleton, au lieu d'être une classe statique):

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

Ah, merci, je n'avais pas pensé à ça! – Malfist

76

Je pense que c'est dommage aussi - un exemple que j'ai tendance à utiliser est Encoding, où Encoding.GetEncoding ("foo") pourrait être Encoding ["Foo"]. Je ne pense pas que cela viendrait souvent, mais à part toute autre chose, il semble juste un peu incohérent de ne pas être disponible.

Je devrais vérifier, mais je suspect il est disponible en IL déjà.

+5

Langage intermédiaire - sorte de langage d'assemblage pour .NET. –

+10

Ce qui m'a amené ici est que j'ai une classe personnalisée qui expose un dictionnaire de valeurs communes utilisées dans mon application via une propriété statique. J'espérais utiliser un indexeur statique pour raccourcir l'accès de GlobalState.State [KeyName] à GlobalState [KeyName]. Cela aurait été sympa. – xr280xr

+1

FWIW, en changeant 'instance' en' static' dans l'IL pour une propriété et une méthode getter sur une propriété par défaut, ilasm se plaint 'd'erreur de syntaxe à token' static''; Je ne suis pas très doué pour m'immiscer dans les affaires de l'IL mais cela ressemble au moins à un non initial. – Amazingant

-2

Ce mot clé fait référence à l'instance actuelle de la classe. Les fonctions membres statiques n'ont pas ce pointeur. Ce mot-clé peut être utilisé pour accéder aux membres depuis les constructeurs, les méthodes d'instance et les accesseurs d'instance (récupéré à partir de msdn). Puisque cela fait référence à une instance de la classe, elle est en conflit avec la nature de static, puisque static n'est pas associé à une instance de la classe.

Une solution de contournement serait la suivante qui vous permet d'utiliser l'indexeur par rapport à un dictionnaire privé afin que vous ayez seulement besoin de créer une nouvelle instance et que vous accédiez à la partie statique.

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

Cela vous permet de sauter l'ensemble d'accéder à un membre de la classe et juste créer une instance de celui-ci et l'indexer.

new ConfigurationManager()["ItemName"] 
+2

est une solution de contournement intéressante, mais 1) il introduit des effets secondaires (création d'un objet instance vide) qui pourraient conduire à la pression de la mémoire et la fragmentation dans certains environnements, 2) les caractères supplémentaires gaspillés par 'new()' auraient pu être utilisés pour le qualificateur nom d'un singleton à la place, comme '.Current' –

+1

Tout comme [la réponse de Juliette] (http://stackoverflow.com/a/401275/1430156), cela ne répond pas à la question de savoir pourquoi les indexeurs statiques ne sont pas supportés. Premièrement, la question ne limite pas le terme "indexeur statique" à "quelque chose qui utilise le mot-clé" this ", et deuxièmement," ceci "dans la syntaxe' chaîne publique this [int index] 'est strictement pas même une utilisation d'un pointeur 'this' (comme cela peut arriver dans le corps des méthodes d'instance), mais juste une autre utilisation du * token *' this'.La syntaxe 'chaîne statique publique this [int index]' pourrait * sembler * un peu contre-intuitive, mais elle serait toujours non ambiguë. –

+1

@ O.R.Mapper Il pourrait tout aussi bien être 'public static string class [int index]'. –

-1

La raison en est qu'il est assez difficile de comprendre exactement ce que vous indexez avec un indexeur statique.

Vous dites que le code bénéficierait d'un indexeur statique, mais le ferait-il vraiment?Tout ce qu'il ferait est de changer ceci:

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

Dans ceci:

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

qui ne fait pas le code mieux en aucune manière; il n'est pas plus petit par beaucoup de lignes de code, il n'est pas plus facile d'écrire grâce à la saisie semi-automatique et il est moins clair, car il cache le fait que vous obtenez quelque chose que vous appelez 'Property' allez lire la documentation sur ce exactement le rendement indexeur ou ensembles, parce qu'il est nullement évident qu'il est une propriété que vous indexez pour, tout à la fois:

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

vous pouvez le lire à haute voix et immédiatement comprendre ce que fait le code. Rappelez-vous que nous voulons écrire un code facile à comprendre (= rapide), pas un code rapide à écrire. Ne confondez pas la vitesse à laquelle vous pouvez définir le code avec la vitesse à laquelle vous terminez les projets.

+0

En désaccord. C'est simplement un point conceptuel. Et le code semble mieux à mon avis, bien que ce soit simplement mon opinion. – ouflak