Унаследованный индексатор C#: другой способ

У меня есть абстрактный родительский класс, который инкапсулирует доступ к массиву MyObjects:

public abstract class MyObjectIterator
{
    public MyObjectIterator(MyObject[] MyObjects) { //constructor }

    public Vector2 [] Coords { //A Get Function }

    public Model[] Params { //A Get Function }

    //THIS ISN'T SAFE! CAN STILL CHANGE MEMBERS OF THE SET
    public MyObject[] MyObjects{ get; protected set; }
}

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

MyObject = Child.MyObjects[i];

но без предоставления set доступа к любому элементу MyObjects.

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

Редактировать:
Я решил использовать этот метод
public MyObject MyObject(int index) { return MyObjects[index]; }, так как он больше всего соответствует тому, что я хотел.


person 3Pi    schedule 15.06.2012    source источник
comment
Обратите внимание, что даже если коллекция доступна только для чтения, возвращаемые MyObject все равно можно редактировать. Если это проблема, вы можете сделать что-то, чтобы выставлять только клоны объектов, или изменить MyObject с class на struct.   -  person Tim S.    schedule 15.06.2012
comment
IMO было бы лучше использовать индексатор вместо метода, если вы решите пойти по этому пути. Функционально он очень похож, но допускает более простое объявление и получение. Вы также можете реализовать IEnumerable<MyObject>, чтобы разрешить итерацию таким образом. Поскольку IEnumerable указывает только доступ для чтения, вам не нужно раскрывать какие-либо установленные возможности.   -  person Tim S.    schedule 15.06.2012
comment
@TimS, я хотел использовать индексатор, но поскольку дочерние классы реализуют индексаторы с одинаковыми аргументами, родительский класс недоступен сразу. Отсюда вопрос (дочерние классы имеют разные типы возвращаемого значения; если бы С# мог перегружаться на основе типа возвращаемого значения, это было бы замечательно...)   -  person 3Pi    schedule 15.06.2012
comment
Технически платформа .NET допускает перегрузку на основе возвращаемых типов; однако C# этого не делает. Если вы действительно хотите пойти и написать MSIL, вы можете получить желаемые функции. В противном случае придется использовать ваш подход или маршрут только для чтения (или что-то еще, кроме индексатора с теми же аргументами).   -  person GGulati    schedule 19.06.2012


Ответы (1)


Существует класс ReadOnlyCollection, который может выполнить то, что вы ищете. Это действует как обертка вокруг массива. Используйте что-то вроде ReadOnlyCollection<MyObject> Data { get { return array.AsReadOnly(); } }. Изменение базового массива повлияет на ReadOnlyCollection. Сама коллекция относительно легкая, поэтому вы можете создавать новую при каждом доступе к свойству или использовать кэширование, если к свойству обращаются часто (либо на сайте вызова, либо внутри самого класса).

Что касается вашего второго вопроса, то ответ положительный. Индексаторы в C# скорее похожи на свойства. Если бы свойство могло быть унаследовано (или необходимо, например, из-за интерфейса), индексатор тоже был бы таким.

person GGulati    schedule 15.06.2012
comment
И уточнить, если дочерний класс реализует свой индексатор, то родительский будет недоступен без приведения к родителю? - person 3Pi; 15.06.2012
comment
Да; дочерняя реализация скроет родительскую. Но если бы вы использовали полиморфизм, Parent[i] использовал бы реализацию родителя, а не выполнял бы код для Child[i] (если бы индексатор был скрыт, а не переопределен [родительский должен быть виртуальным]). - person GGulati; 15.06.2012