ReadOnlyCollection или IEnumerable для представления членских наборов?

Один из способов - использовать наборы:

>>> set([1,2,6,8]) - set([2,3,5,8])
set([1, 6])
117
задан Erik Öjebo 29 January 2009 в 12:20
поделиться

5 ответов

более современное решение

, Если Вам не нужен внутренний набор, чтобы быть изменяемыми, Вы могли использовать System.Collections.Immutable пакет, изменить свой тип поля, чтобы быть неизменным набором и затем выставить это непосредственно - принятие Foo само неизменно, конечно.

Обновленный ответ для рассматривания вопроса более непосредственно

Является там какой-либо причиной выставить внутренний набор как ReadOnlyCollection, а не IEnumerable, если код вызова только выполняет итерации по набору?

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

ICollection<Foo> evil = (ICollection<Foo>) bar.Foos;
evil.Add(...);

затем уверенный, никакой вред не будет причинен, если Вы просто возвратите набор непосредственно. Я обычно пытаюсь быть более параноиком, чем это все же.

Аналогично, как Вы говорите: если Вы только [1 110] потребность IEnumerable<T>, то, почему связь сами с чем-либо более сильным?

Исходный ответ

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

public IEnumerable<Foo> Foos {
    get { return foos.Skip(0); }
}

(Существует много других опций для обертывания тривиально - хорошая вещь, которая приблизительно Skip по Выбору/Где - то, что нет никакого делегата для выполнения бессмысленно для каждого повторения.)

, Если Вы не используете.NET 3.5, можно записать очень простую обертку, чтобы сделать то же самое:

public static IEnumerable<T> Wrapper<T>(IEnumerable<T> source)
{
    foreach (T element in source)
    {
        yield return element;
    }
}
93
ответ дан Jon Skeet 5 November 2019 в 08:51
поделиться

Если только необходимо выполнить итерации через набор:

foreach (Foo f in bar.Foos)

затем возврат IEnumerable достаточно.

, Если Вам нужен произвольный доступ к объектам:

Foo f = bar.Foos[17];

затем переносят его в ReadOnlyCollection.

41
ответ дан Vojislav Stojkovic 5 November 2019 в 08:51
поделиться

Если Вы делаете это затем нет ничего останавливающего Ваши вызывающие стороны, бросающие IEnumerable назад к ICollection и затем изменяющие его. ReadOnlyCollection удаляет эту возможность, хотя все еще возможно получить доступ к базовому перезаписываемому набору через отражение. Если коллекция является небольшой затем, безопасный и простой способ обойти эту проблему состоит в том, чтобы возвратить копию вместо этого.

31
ответ дан Stu Mackellar 5 November 2019 в 08:51
поделиться

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

0
ответ дан 5 November 2019 в 08:51
поделиться

Я избегаю использования ReadOnlyCollection, насколько это возможно, это на самом деле значительно медленнее, чем использование обычного списка. Смотрите этот пример:

List<int> intList = new List<int>();
        //Use a ReadOnlyCollection around the List
        System.Collections.ObjectModel.ReadOnlyCollection<int> mValue = new System.Collections.ObjectModel.ReadOnlyCollection<int>(intList);

        for (int i = 0; i < 100000000; i++)
        {
            intList.Add(i);
        }
        long result = 0;

        //Use normal foreach on the ReadOnlyCollection
        TimeSpan lStart = new TimeSpan(System.DateTime.Now.Ticks);
        foreach (int i in mValue)
            result += i;
        TimeSpan lEnd = new TimeSpan(System.DateTime.Now.Ticks);
        MessageBox.Show("Speed(ms): " + (lEnd.TotalMilliseconds - lStart.TotalMilliseconds).ToString());
        MessageBox.Show("Result: " + result.ToString());

        //use <list>.ForEach
        lStart = new TimeSpan(System.DateTime.Now.Ticks);
        result = 0;
        intList.ForEach(delegate(int i) { result += i; });
        lEnd = new TimeSpan(System.DateTime.Now.Ticks);
        MessageBox.Show("Speed(ms): " + (lEnd.TotalMilliseconds - lStart.TotalMilliseconds).ToString());
        MessageBox.Show("Result: " + result.ToString());
3
ответ дан 24 November 2019 в 01:59
поделиться
Другие вопросы по тегам:

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