Question

Pourquoi les indexeurs statiques sont-ils interdits en C #? Je ne vois pas pourquoi ils ne devraient pas être autorisés et, en outre, ils pourraient être très utiles.

Par exemple:

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

Le code ci-dessus gagnerait grandement à un indexeur statique. Cependant, il ne compilera pas car les indexeurs statiques ne sont pas autorisés. Pourquoi est-ce vrai?

Était-ce utile?

La solution

La notation de l'indexeur nécessite une référence à this . Les méthodes statiques ne faisant pas 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 consiste à utiliser un modèle de singleton comme suit:

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

Vous pouvez maintenant appeler Utilities.ConfigurationManager [" someKey "] en utilisant la notation d'indexeur.

Autres conseils

Je pense que cela n'a pas été jugé utile. Je pense que c’est dommage aussi. Un exemple que j’ai tendance à utiliser est l’encodage, où Encoding.GetEncoding ("foo") pourrait être Encodage ["Foo"] . Je ne pense pas que cela arriverait très souvent, mais en dehors de tout ce qui se passe, cela semble un peu incohérent de ne pas être disponible.

Je devrais vérifier, mais je soupçonne qu'il est déjà disponible en langage intermédiaire (IL).

Pour contourner le problème, vous pouvez définir un indexeur d'instance sur un objet singleton / statique (par exemple, 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 ... }
}

Avec les nouvelles constructions de C # 6, vous pouvez simplifier le motif singleton avec un corps d’expression de propriété. Par exemple, j'ai utilisé le raccourci suivant qui fonctionne bien avec le code-lentille:

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

Il présente l’avantage supplémentaire de pouvoir être remplacé pour la mise à niveau de code ancien et l’unification de l’accès aux paramètres de votre application.

J'avais également besoin (bien plus, d'une manière agréable) d'un indexeur statique pour stocker les attributs, j'ai donc trouvé une solution de contournement quelque peu délicate:

Dans la classe pour laquelle vous voulez un indexeur statique (ici: Element), créez une sous-classe du même nom + "Dict". Donnez-lui une instruction statique en lecture seule comme instance de ladite sous-classe, puis ajoutez l'indexeur souhaité.

Enfin, ajoutez la classe en tant qu'importation statique (d'où la sous-classe qui n'expose que le champ statique).

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

et vous pouvez ensuite l'utiliser en majuscule en tant que Type ou sans dictionnaire:

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

Mais hélas, si l'on utilisait réellement l'objet comme "valeur", alors le texte ci-dessous serait toujours plus court (au moins comme déclaration), et fournirait également une conversion immédiate:

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

Le mot-clé this fait référence à l'instance actuelle de la classe. Les fonctions membres statiques n'ont pas de pointeur this. Le mot-clé this peut être utilisé pour accéder aux membres depuis des constructeurs, des méthodes d'instance et des accesseurs d'instance. (Extrait de msdn ). Puisque ceci fait référence à une instance de la classe, il entre en conflit avec la nature de static, ce dernier n'étant pas associé à une instance de la classe.

Une solution de contournement serait la suivante, qui vous permet d’utiliser l’indexeur contre un fichier privé. Dictionnaire, il vous suffit donc de créer une nouvelle instance et d’accéder à 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>();        
}

Ceci vous permet de sauter l’ensemble du processus en accédant à un membre de la classe et de simplement en créer une instance et l’indexer.

    new ConfigurationManager()["ItemName"]

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 que cela ferait serait de changer cela:

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

Dans ceci:

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

qui ne rend pas le code meilleur en aucune façon; il n’est pas plus petit de plusieurs 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 et définissez quelque chose que vous appelez «Propriété» et oblige en réalité le lecteur à: Allez lire la documentation sur ce que l'indexeur retourne ou définit exactement, car il n'est pas évident que ce soit une propriété pour laquelle vous indexez, alors qu'avec les deux:

<*>

Vous pouvez le lire à voix haute et comprendre immédiatement ce que fait le code.

N'oubliez pas que nous voulons écrire du code facile à comprendre (= rapide), pas du code rapide à écrire. Ne vous méprenez pas sur la vitesse à laquelle vous pouvez établir le code avec la vitesse à laquelle vous terminez des projets.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top