Почему C# не реализует индексируемые свойства?

Я знаю, я знаю... Ответ Eric Lippert на этот вид вопроса обычно - что-то как, "потому что это не стоило стоимости разработки, реализации, тестирования и документирования его".

Но тем не менее, я хотел бы лучшее объяснение... Я читал это сообщение в блоге о новом C# 4 функции, и в разделе о COM Interop, следующая часть привлекла мое внимание:

Между прочим, этот код использует еще одну новую функцию: индексируемые свойства (более тщательно изучают те квадратные скобки после Диапазона.), Но эта функция доступна только для взаимодействующего с COM; Вы не можете создать свои собственные индексируемые свойства в C# 4.0.

Хорошо, но почему? Я уже знал и сожалел, что не было возможно создать индексируемые свойства в C#, но это предложение заставило меня думать снова об этом. Я вижу несколько серьезных оснований реализовать его:

  • CLR поддерживает его (например, PropertyInfo.GetValue имеет index параметр), поэтому жаль, что мы не можем использовать в своих интересах его в C#
  • это поддерживается для взаимодействующего с COM, как показано в статье (использующий динамическую отправку)
  • это реализовано в VB.NET
  • уже возможно создать индексаторы, т.е. применить индекс к самому объекту, таким образом, это, вероятно, не было бы никакое грандиозное предприятие расширить идею свойствам, сохранив тот же синтаксис и просто замену this с именем свойства

Это позволило бы писать такие вещи:

public class Foo
{
    private string[] _values = new string[3];
    public string Values[int index]
    {
        get { return _values[index]; }
        set { _values[index] = value; }
    }
}

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

Это очень легко сделать, но раздражающий... Таким образом, возможно, компилятор мог сделать это для нас! Опция состояла бы в том, чтобы генерировать внутренний класс, который реализует индексатор, и выставьте его через общедоступный универсальный интерфейс:

// interface defined in the namespace System
public interface IIndexer
{
    TValue this[TIndex index]  { get; set; }
}

public class Foo
{
    private string[] _values = new string[3];

    private class <>c__DisplayClass1 : IIndexer
    {
        private Foo _foo;
        public <>c__DisplayClass1(Foo foo)
        {
            _foo = foo;
        }

        public string this[int index]
        {
            get { return _foo._values[index]; }
            set { _foo._values[index] = value; }
        }
    }

    private IIndexer <>f__valuesIndexer;
    public IIndexer Values
    {
        get
        {
            if (<>f__valuesIndexer == null)
                <>f__valuesIndexer = new <>c__DisplayClass1(this);
            return <>f__valuesIndexer;
        }
    }
}

Но конечно, в этом случае свойство на самом деле возвратило бы a IIndexer, и действительно не было бы индексируемое свойство... Было бы лучше генерировать реальное индексируемое свойство CLR.

Что Вы думаете? Хотели бы Вы видеть эту функцию в C#? В противном случае, почему?

80
задан Thomas Levesque 10 May 2010 в 22:30
поделиться

5 ответов

Вот как мы разработали C # 4.

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

Затем мы сгруппировали функции как «это плохо, мы никогда не должны этого делать», «это круто, мы должны это сделать» и «это хорошо, но давайте не будем делать это в этот раз».

Затем мы посмотрели, сколько бюджета у нас было на проектирование, внедрение, тестирование, документирование, поставку и поддержку необходимых функций, и обнаружили, что мы на 100% превышаем бюджет.

Итак, мы переместили кучу вещей из ведра «надо иметь» в ведро «хорошо иметь».

Проиндексированные свойства никогда не находились в верхней части списка "обязательных". Они очень низкие в списке «хороших» и заигрывают со списком «плохих идей».

Каждая минута, которую мы тратим на разработку, внедрение, тестирование, документирование или поддержку хорошей функции X, - это минута, которую мы не можем потратить на отличные функции A, B, C, D, E, F и G. Мы должны безжалостно расставлять приоритеты, чтобы что мы делаем только самые лучшие функции. Индексированные свойства были бы хороши, но даже близко не достаточно хороши, чтобы их можно было реализовать.

113
ответ дан 24 November 2019 в 09:54
поделиться

Индексатор в C# является индексированным свойством. По умолчанию оно называется Item (и вы можете обращаться к нему как к таковому, например, из VB), и вы можете изменить его с помощью IndexerNameAttribute, если хотите.

Я не уверен, почему именно так было задумано, но, похоже, это намеренное ограничение. Тем не менее, оно согласуется с Framework Design Guidelines, которые рекомендуют подход, когда неиндексированное свойство возвращает индексируемый объект для коллекций-членов. Т.е. "быть индексируемым" - это свойство типа; если он индексируется более чем одним способом, то его действительно следует разделить на несколько типов.

19
ответ дан 24 November 2019 в 09:54
поделиться

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

class Foo
{
    public Values Values { ... }
}

class Values
{
    public string this[int index] { ... }    
}

foo.Values[0]

Я лично предпочел бы видеть только один способ сделать что-то, а не 10 способов. Но, конечно, это субъективное мнение.

14
ответ дан 24 November 2019 в 09:54
поделиться

Я бы сказал, что они не добавили его, потому что это не стоило затрат на его разработку, внедрение, тестирование и документирование.

Шутя в сторону, это, вероятно, потому, что обходные пути просты, и эта функция никогда не сокращает время по сравнению с выгодами. Я не удивлюсь, если в будущем это покажется изменением.

Вы также забыли упомянуть, что более простой способ решения проблемы - это просто создать обычный метод:

public void SetFoo(int index, Foo toSet) {...}
public Foo GetFoo(int index) {...}
1
ответ дан 24 November 2019 в 09:54
поделиться

Другой обходной путь указан в Простое создание свойств, поддерживающих индексацию в C # , что требует меньше работы.

РЕДАКТИРОВАТЬ : я должен также добавить, что в ответ на исходный вопрос, если мы сможем реализовать желаемый синтаксис с поддержкой библиотеки, то я думаю, что должны быть очень веские аргументы, чтобы добавить его непосредственно в язык, чтобы свести к минимуму языковой раздувание.

2
ответ дан 24 November 2019 в 09:54
поделиться
Другие вопросы по тегам:

Похожие вопросы: