Один из способов - использовать наборы:
>>> set([1,2,6,8]) - set([2,3,5,8])
set([1, 6])
более современное решение
, Если Вам не нужен внутренний набор, чтобы быть изменяемыми, Вы могли использовать 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;
}
}
Если только необходимо выполнить итерации через набор:
foreach (Foo f in bar.Foos)
затем возврат IEnumerable достаточно.
, Если Вам нужен произвольный доступ к объектам:
Foo f = bar.Foos[17];
затем переносят его в ReadOnlyCollection.
Если Вы делаете это затем нет ничего останавливающего Ваши вызывающие стороны, бросающие IEnumerable назад к ICollection и затем изменяющие его. ReadOnlyCollection удаляет эту возможность, хотя все еще возможно получить доступ к базовому перезаписываемому набору через отражение. Если коллекция является небольшой затем, безопасный и простой способ обойти эту проблему состоит в том, чтобы возвратить копию вместо этого.
Иногда можно хотеть использовать интерфейс, возможно, потому что Вы хотите дразнить набор во время поблочного тестирования. Посмотрите мой запись в блоге для добавления Вашего собственного интерфейса к ReadonlyCollection при помощи адаптера.
Я избегаю использования 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());