Почему нельзя определить универсальные индексаторы в .NET? - PullRequest
42 голосов
/ 30 января 2009

Почему вы не можете создать универсальный индексатор в .NET?

следующий код выдает ошибку компилятора:

   public T this<T>[string key]
   {
      get { /* Return generic type T. */ }
   }

Означает ли это, что вы не можете создать универсальный индексатор для универсальной коллекции элементов?

Ответы [ 7 ]

27 голосов
/ 01 февраля 2010

Вот место, где это было бы полезно. Скажем, у вас есть строго типизированный 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];
}
18 голосов
/ 30 января 2009

Свойства не могут быть общими в C # 2.0 / 3.0, поэтому у вас не может быть универсального индексатора.

16 голосов
/ 30 января 2009

Не знаю почему, но индексаторы - это просто синтаксический сахар. Вместо этого напишите универсальный метод, и вы получите ту же функциональность. Например:

   public T GetItem<T>(string key)
   {
      /* Return generic type T. */
   }
11 голосов
/ 30 января 2009

можно; просто удалите часть <T> из вашей декларации, и она будет работать нормально. т.е.

public T this[string key]
{
   get { /* Return generic type T. */ }
}

(Предполагается, что ваш класс является общим с параметром типа с именем T).

2 голосов
/ 20 сентября 2012

Мне нравится возможность иметь индексатор без раздачи прямая ссылка на «проиндексированный» элемент. Я написал простую Класс обратного вызова "callback" ниже ...

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

}

работает как чемпион, особенно если вы хотите контролировать доступ к ваш список или делать какие-либо специальные операции, когда что-то происходит.

1 голос
/ 30 января 2009

Единственное, что я могу придумать, это использовать что-то вроде:

var settings = ConfigurationSection.AppSettings;
var connectionString = settings<string>["connectionString"];
var timeout = settings<int>["timeout"];

Но на самом деле это ничего не купит. Вы только что заменили круглые скобки (как в (int)settings["timeout"]) на угловые скобки, но не получили дополнительную безопасность типов, поскольку вы можете свободно делать

var timeout = settings<int>["connectionString"];

Если у вас есть что-то строго, но не статически, вы можете подождать, пока C # 4.0 с ключевым словом dynamic .

0 голосов
/ 14 апреля 2018

В недавнем C-sharp вы можете объявить тип возвращаемого значения как "динамический". Это то же самое, что и использование «объекта», за исключением того, что среда выполнения C # позволит вам использовать его в коде, как если бы он был тем типом, о котором вы думаете, а затем проверять во время выполнения, чтобы убедиться, что вы правы ... *

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...