Почему невозможно определить общие индексы в .NET?
Почему вы не можете создать общий индекс в .NET?
следующий код генерирует ошибку компилятора:
public T this<T>[string key]
{
get { /* Return generic type T. */ }
}
Означает ли это, что вы не можете создать общий индекс для общей коллекции членов?
Ответы
Ответ 1
Единственное, что я могу думать об этом, можно использовать в следующих строках:
var settings = ConfigurationSection.AppSettings;
var connectionString = settings<string>["connectionString"];
var timeout = settings<int>["timeout"];
Но это на самом деле ничего не покупает. Вы только что заменили раунд parens (как в настройках (int) [ "timeout" ]) с помощью угловых скобок, но не получили дополнительной безопасности типа, поскольку вы можете свободно делать
var timeout = settings<int>["connectionString"];
Если у вас есть что-то сильно, но не статически напечатанное, вам может потребоваться дождаться С# 4.0 с его динамическим ключевым словом.
Ответ 2
Здесь место, где это было бы полезно. Скажем, у вас есть строго типизированный OptionKey<T>
для объявления параметров.
public static class DefaultOptions
{
public static OptionKey<bool> SomeBooleanOption { get; }
public static OptionKey<int> SomeIntegerOption { get; }
}
Если параметры отображаются через интерфейс IOptions
:
public interface IOptions
{
/* since options have a default value that can be returned if nothing's
* been set for the key, it'd be nice to use the property instead of the
* pair of methods.
*/
T this<T>[OptionKey<T> key]
{
get;
set;
}
T GetOptionValue<T>(OptionKey<T> key);
void SetOptionValue<T>(OptionKey<T> key, T value);
}
Затем код мог бы использовать универсальный индекс в качестве красивого строго типизированного хранилища опций:
void Foo()
{
IOptions o = ...;
o[DefaultOptions.SomeBooleanOption] = true;
int integerValue = o[DefaultOptions.SomeIntegerOption];
}
Ответ 3
Свойства не могут быть общими в С# 2.0/3.0, поэтому вы не можете иметь общий индекс.
Ответ 4
Я не знаю, почему, но индексаторы - это просто синтаксический сахар. Вместо этого напишите общий метод, и вы получите ту же функциональность. Например:
public T GetItem<T>(string key)
{
/* Return generic type T. */
}
Ответ 5
Вы можете; просто отбросьте часть <T>
из вашей декларации, и она будет работать нормально. то есть.
public T this[string key]
{
get { /* Return generic type T. */ }
}
(Предполагая, что ваш класс является общим с параметром типа с именем T
).
Ответ 6
Мне нравится возможность иметь индексатора без раздачи
прямая ссылка на "индексированный" элемент. Я написал простой
"перезванивать" класс индексатора ниже...
R = возвращаемый тип из индексатора
P = переданный тип в индекс
Весь индекс, который действительно выполняет, передает операции
развертыватель и разрешить им управлять тем, что на самом деле происходит
и возвращается.
public class GeneralIndexer<R,P>
{
// Delegates
public delegate R gen_get(P parm);
public delegate void gen_set(P parm, R value);
public delegate P[] key_get();
// Events
public event gen_get GetEvent;
public event gen_set SetEvent;
public event key_get KeyRequest;
public R this[P parm]
{
get { return GetEvent.Invoke(parm); }
set { SetEvent.Invoke(parm, value); }
}
public P[] Keys
{
get
{
return KeyRequest.Invoke();
}
}
}
Чтобы использовать его в программе или классе:
private GeneralIndexer<TimeSpan, string> TimeIndex = new GeneralIndexer<TimeSpan,string>();
{
TimeIndex.GetEvent += new GeneralIndexer<TimeSpan, string>.gen_get(TimeIndex_GetEvent);
TimeIndex.SetEvent += new GeneralIndexer<TimeSpan, string>.gen_set(TimeIndex_SetEvent);
TimeIndex.KeyRequest += new GeneralIndexer<TimeSpan, string>.key_get(TimeIndex_KeyRequest);
}
работает как чемпион, особенно если вы хотите контролировать доступ к
ваш список или какие-либо специальные операции, когда что-то доступно.