Pergunta

Por que indexadores estáticos anulado em C #? Eu não vejo nenhuma razão para que eles não devem ser permitidos e, além disso, que poderia ser muito útil.

Por exemplo:

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

O código acima iria beneficiar muito de um indexador de estática. No entanto, não irá compilar porque indexadores estáticos não são permitidos. Por que isso acontece?

Foi útil?

Solução

notação indexador requer uma referência para this. Desde métodos estáticos não têm uma referência a uma instância específica da classe, você não pode usar this com eles, e, consequentemente, você não pode usar a notação de indexador em métodos estáticos.

A solução para o seu problema está usando um padrão singleton da seguinte forma:

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

Agora você pode chamar Utilities.ConfigurationManager["someKey"] usando a notação de indexador.

Outras dicas

Eu acredito que não foi considerada para ser extremamente útil. Eu acho que é uma vergonha também - um exemplo que eu tendem a usar é Encoding, onde Encoding.GetEncoding("foo") poderia ser Encoding["Foo"]. Eu não acho que ele iria vir para cima muito , muitas vezes, mas para além de qualquer outra coisa que só se sente um pouco inconsistente não estar disponível.

Eu teria que verificar, mas eu suspeito está disponível em IL (Intermediate Language) já.

Como uma solução alternativa, você pode definir um indexador instância em um objeto singleton / static (dizer que ConfigurationManager é um singleton, em vez de ser uma classe estática):

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

Com as construções mais recentes em C # 6, você pode simplificar o padrão Singleton com um corpo expressão de propriedade. Por exemplo, eu usei o seguinte atalho que funciona muito bem com o código-lense:

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

Ele tem a vantagem de ser achado-substituir-capazes para atualizar código antigo e unificar o acesso a sua aplicação configurações.

Eu também estava precisando (bem, mais como bom de se ter) de um indexador estática para atributos de loja, então eu descobri uma solução um pouco estranho:

Dentro da classe que você quer ter um indexador estático (aqui: Element), criar uma subclasse do mesmo nome + "Dict". Dê-lhe um estático readonly como exemplo da referida subclasse, e depois adicionar o seu indexador desejado.

Por último, adicione a classe como a importação estática (daí a subclasse apenas expor o campo estático).

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

e então você pode usá-lo tanto capitalizados como Type, ou sem, como dicionário:

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

Mas, infelizmente, se alguém fosse realmente usar objeto como "valor" Type, então a seguir seria ainda mais curto (pelo menos como declaração), e também fornecer Typecasting imediata:

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

A esta palavra-chave refere-se a instância atual da classe. funções de membro estático não tem um este ponteiro. A esta palavra-chave pode ser usada para acessar membros de dentro construtores, métodos de instância, e acessores de instância. (Recuperado de MSDN ). Desde essa referências uma instância da classe que ele incompatível com a natureza de estática, uma vez estático não está associado a uma instância da classe.

Uma solução alternativa seria o seguinte, que permite usar o indexador contra uma privada Dicionário assim você só precisa criar uma nova instância e você acessar a parte estática.

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

Isso permite que você pule acessando a todo membro da classe e apenas criar uma instância dele e indexá-lo.

    new ConfigurationManager()["ItemName"]

A razão é porque é muito difícil entender o que exatamente você está indexando com um indexador estático.

Você diz que o código se beneficiaria de um indexador estática, mas seria realmente? Tudo o que fazer é mudar esta:

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

Dentro deste:

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

que não faz o código melhor de qualquer forma; não é menor por muitas linhas de código, não é mais fácil de escrever, graças a autocomplete e é menos clara, como ele esconde o fato de que você está recebendo e definir algo que chamamos de 'propriedade' e ele realmente força o leitor a Vá ler a documentação sobre o que exatamente o indexador retorna ou conjuntos, porque ele não é de forma óbvio que é uma propriedade que está a indexar para, enquanto que com ambos:

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

Você pode lê-lo em voz alta e entender imediatamente o que o código faz.

Lembre-se que nós queremos escrever código que é fácil (= rápido) para entender, não o código que é rápido para escrever. Não confunda a velocidade na qual você pode estabelecer o código com a velocidade em que você concluir projetos.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top