2008-12-30 5 views
91

Почему статические индексы запрещены в C#? Я не вижу причин, по которым их нельзя допускать, и, кроме того, они могут быть очень полезными.Статические индексы?

Например:

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

Приведенный выше код будет извлечь большую пользу из статического индексатора. Однако он не будет компилироваться, потому что статические индексы не допускаются. Почему это так?

+0

Далее мне нужна прямая реализация IEnumerable в статическом классе, поэтому я могу сделать 'foreach (var enum in Enum)' :) – nawfal

ответ

55

Индексатор обозначения требует ссылки до this. Поскольку статические методы не имеют ссылки на конкретный экземпляр класса, вы не можете использовать с ними this, и, следовательно, вы не можете использовать нотацию индексатора для статических методов.

Решение вашей проблемы использует одноплодной шаблон следующим образом:


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

Теперь вы можете вызвать Utilities.ConfigurationManager["someKey"] используя индексатор обозначения.

+90

Но почему индекеры должны использовать «это»? Ему не нужно обращаться к данным экземпляра – Malfist

+68

+1 за комментарий Малфиста. Просто потому, что он использует «это» для индексатора индекса, это не значит, что они не могли придумать другой синтаксис. –

+30

Согласовано. Вы умоляете вопрос. Вы в основном сказали, что причина, по которой это запрещено, - это потому, что это запрещено. -1, потому что вопрос был «почему это не разрешено?» – xr280xr

5

В работе вокруг, вы можете определить экземпляр индексатор на одноплодной/статический объект (скажем, что ConfigurationManager одноэлементно, вместо того, чтобы быть статический класс):

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

Ах, спасибо, я не думал об этом! – Malfist

76

Я считаю, что это считалось не очень полезным. Я думаю, что это тоже позор - примером, который я обычно использую, является Encoding, где Encoding.GetEncoding ("foo") может быть Encoding ["Foo"]. Я не думаю, что это очень часто включало , но в стороне от всего остального он просто чувствует себя немного непоследовательно, чтобы не быть доступным.

Мне нужно было бы проверить, но я подозреваемый он уже доступен в IL.

+5

Промежуточный язык - вид ассемблера для .NET. –

+10

Что привело меня сюда: у меня есть пользовательский класс, который предоставляет словарь общих значений, используемых во всем моем приложении, через статическое свойство. Я надеялся использовать статический индексатор, чтобы сократить доступ с GlobalState.State [KeyName] до всего лишь GlobalState [KeyName]. Было бы хорошо. – xr280xr

+1

FWIW, изменяя 'instance' на' static' в IL для свойства и метода getter по умолчанию, приводит к тому, что ilasm жалуется на синтаксическую ошибку в токене «static»; Я не очень люблю вмешиваться в дела ИЛ, но это звучит, по крайней мере, как начальный номер. – Amazingant

-2

Это ключевое слово относится к текущему экземпляру класса. У статических функций-членов нет указателя. Это ключевое слово можно использовать для доступа к элементам из конструкторов, методов экземпляра и экземпляров экземпляров. (Извлечено из msdn). Поскольку это ссылается на экземпляр класса, он конфликтует с природой static, поскольку static не ассоциируется с экземпляром класса.

Возможным обходным решением является использование индексатора для частного Dictionary, поэтому вам нужно создать новый экземпляр и получить доступ к статической части.

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

Это позволяет пропустить весь доступ к члену класса и просто создать экземпляр его и проиндексировать его.

new ConfigurationManager()["ItemName"] 
+2

его интересное обходное решение, но 1) оно вводит побочные эффекты (создание пустого экземпляра объекта), что может привести к давлению и фрагментации памяти в некоторых средах; 2) могут использоваться дополнительные символы, опустошенные 'new()' вместо имени классификатора singleton, например '.Current' –

+1

Как и [ответ Джульетты] (http://stackoverflow.com/a/401275/1430156), это не отвечает на вопрос, почему статические индексы не поддерживаются.Во-первых, вопрос не ограничивает термин «статический указатель» «тем, что использует ключевое слово this», а во-вторых, 'this' в синтаксисе' public string этот [int index] 'строго говоря, даже не используется указателя 'this' (как это может происходить в теле методов экземпляра), а просто другое использование * токена *' this'. Синтаксис 'public static string this [int index]' может * выглядеть * немного противоречивым, но он все равно будет недвусмысленным. –

+1

@ O.R.Mapper Это также может быть 'public static string class [int index]'. –

-1

Причина в том, что довольно сложно понять, что именно вы индексируете с помощью статического индексатора.

Вы говорите, что код будет полезен для статического индексатора, но будет ли это на самом деле?Все это будет сделать, это изменить:

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

В это:

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

, который не делает код лучше в любом случае; он не меньше по многим строкам кода, писать автозаполнение проще, и это менее понятно, поскольку он скрывает тот факт, что вы получаете и устанавливаете то, что вы называете «Свойством», и это на самом деле заставляет читателя почитайте документацию о том, что именно возвращает индексатор или наборы, потому что это никоим образом не очевидно, что это свойство, которое вы индексирование для, в то время как с обоими:

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

вы можете прочитать его вслух и сразу понять, что делает код.

Помните, что мы хотим написать код, который легко (= быстро) понять, а не код, который быстро записывается. Не ошибайтесь скорость, с которой вы можете сложить код, со скоростью, с которой вы завершаете проекты.

+0

Не согласен. Это всего лишь концептуальная точка. И код выглядит лучше, на мой взгляд, хотя это только мое мнение. – ouflak