2008-12-30 33 views
91

¿Por qué los indexadores estáticos no se permiten en C#? No veo ninguna razón por la cual no se les permita y, además, podrían ser muy útiles.Indicadores estáticos?

Por ejemplo:

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

El código anterior se beneficiaría enormemente de un indizador de estática. Sin embargo, no se compilará porque los indexadores estáticos no están permitidos. ¿Por qué esto es tan?

+0

Siguiente Quiero implementación directa de IEnumerable en la clase estática, así que puedo hacer 'foreach (var enum en Enum)' :) – nawfal

Respuesta

55

notación paso a paso requiere una referencia a this. Como los métodos estáticos no tienen una referencia a una instancia particular de la clase, no puede usar this con ellos y, en consecuencia, no puede usar la notación del indexador en métodos estáticos.

La solución a su problema es el uso de un patrón singleton de la siguiente manera:


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

Ahora puede llamar Utilities.ConfigurationManager["someKey"] usando la notación indexador.

+90

¿Pero por qué el indexador tiene que usar 'esto'? No tiene que acceder a los datos de instancia – Malfist

+68

+1 para el comentario de Malfist. El hecho de que utilice "esto" para un indexador de instancias no significa que no puedan encontrar otra sintaxis. –

+30

De acuerdo. Estás mendigando la pregunta. Básicamente, has dicho que la razón por la que no está permitido es porque no está permitido. -1 porque la pregunta era "¿por qué no está permitido?" – xr280xr

5

Como solución alternativa, se puede definir un indexador instancia en un objeto singleton/estática (dicen que ConfigurationManager es un producto único, en lugar de ser una clase estática):

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

¡Ah, gracias, no había pensado en eso! – Malfist

76

Creo que se consideró que no era terriblemente útil. También creo que es una lástima, un ejemplo que suelo usar es Encoding, donde Encoding.GetEncoding ("foo") podría ser Encoding ["Foo"]. No creo que salga muy a menudo, pero aparte de cualquier otra cosa, parece un poco inconsistente no estar disponible.

Tendría que verificar, pero I sospechoso ya está disponible en IL.

+5

Idioma intermedio - tipo de lenguaje de ensamblaje para .NET. –

+10

Lo que me trajo aquí es que tengo una clase personalizada que expone un diccionario de valores comunes utilizados en toda mi aplicación a través de una propiedad estática. Esperaba usar un indexador estático para acortar el acceso de GlobalState.State [KeyName] a solo GlobalState [KeyName]. Hubiera sido bueno. – xr280xr

+1

FWIW, el cambio de 'instance' a' static' en el IL para una propiedad y el método getter en una propiedad predeterminada da como resultado ilasm quejándose 'error de sintaxis en el token 'static''; No soy bueno para entrometerme en los asuntos de IL, pero eso suena como al menos un no inicial. – Amazingant

-2

La palabra clave se refiere a la instancia actual de la clase. Las funciones de miembro estático no tienen este puntero. La palabra clave this se puede usar para acceder a miembros desde dentro de constructores, métodos de instancia y accesadores de instancia (recuperado de msdn). Como esto hace referencia a una instancia de la clase, entra en conflicto con la naturaleza de estática, ya que estática no está asociada con una instancia de la clase.

Una solución alternativa sería la siguiente que le permite usar el indexador contra un diccionario privado , por lo que solo necesita crear una nueva instancia y acceder a la 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>();   
} 

Esto le permite saltar la totalidad acceder a un miembro de la clase y acaba de crear una instancia de ella y el índice.

new ConfigurationManager()["ItemName"] 
+2

es una solución interesante, pero 1) introduce efectos secundarios (creación de un objeto de instancia vacío) que podría generar presión de memoria y fragmentación en algunos entornos, 2) los caracteres adicionales desperdiciados por 'new()' podrían haberse utilizado para el nombre calificador de un singleton en su lugar, como '.Current' –

+1

Al igual que [la respuesta de Juliet] (http://stackoverflow.com/a/401275/1430156), esto no responde a la pregunta de por qué los indexadores estáticos no son compatibles. Primero, la pregunta no restringe el término "indexador estático" a "algo que usa la palabra clave' this' ", y segundo,' this' en la sintaxis 'cadena pública this [int index]' es estrictamente hablando ni siquiera un uso de un puntero 'this' (como puede ocurrir en el cuerpo de los métodos de instancia), pero solo otro uso del * token *' this'.La sintaxis 'cadena estática pública este [índice int]' podría * verse * un poco contra intuitiva, pero aún sería inequívoca. –

+1

@ O.R.Mapper Podría ser '' public static string class [int index] '. –

-1

La razón es porque es bastante difícil entender qué es exactamente lo que está indexando con un indexador estático.

Usted dice que el código se beneficiaría de un indexador estático, pero ¿realmente?Todo lo que podría hacer es cambiar esta situación:

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

En esto:

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

que no hace el mejor código de ninguna manera; no es más pequeño por muchas líneas de código, no es más fácil de escribir gracias a la función autocompletar y es menos claro, ya que oculta el hecho de que está obteniendo y configurando algo que llama 'Propiedad' y realmente obliga al lector a ve a leer la documentación sobre qué es exactamente el indexador devoluciones o conjuntos, ya que no es en absoluto evidente que se trata de una propiedad que está indexación para, mientras tanto:

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

usted puede leer en voz alta e inmediatamente entender lo que hace el código

Recuerda que queremos escribir código que sea fácil de entender (= rápido), no código que sea rápido de escribir. No confunda la velocidad con la que puede establecer el código con la velocidad a la que completa los proyectos.

+0

No estoy de acuerdo. Eso es solo un punto conceptual. Y el código se ve mejor en mi opinión, aunque esa es simplemente mi opinión. – ouflak

Cuestiones relacionadas