о version
поле
Update1:
В моей памяти у многих (может быть, всех?) Коллекций в BCL есть поле version
.
Сначала о foreach
:
в соответствии с этой ссылкой MSDN
Оператор foreach повторяет группу встроенных операторов для каждого элемента в массиве или коллекции объектов. Оператор foreach используется для перебора коллекции для получения необходимой информации, но не должен использоваться для изменения содержимого коллекции во избежание непредсказуемых побочных эффектов.
Во многих других коллекциях version
защищен, данные не изменяются в течение foreach
Например, HashTable
MoveNext()
:
public virtual bool MoveNext()
{
if (this.version != this.hashtable.version)
{
throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_EnumFailedVersion"));
}
..........
}
Но в методе SortedSet<T>
MoveNext()
:
public bool MoveNext()
{
this.tree.VersionCheck();
if (this.version != this.tree.version)
{
ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_EnumFailedVersion);
}
....
}
UPDATE2:
Но цикл O (N) может быть не только для version
, но и для свойства Count
.
Поскольку MSDN GetViewBetween сказал:
Этот метод возвращает представление диапазона элементов, которые попадают между lowerValue и upperValue, как определено компаратором .... Вы можете вносить изменения как в представление, так и в базовый SortedSet (Of T) .
Таким образом, для каждого обновления необходимо синхронизировать поле count
(ключ и значение уже совпадают). Чтобы убедиться, что Count
правильный
Существовали две политики для достижения цели:
- от Microsoft
- Моно
First.MS в своем коде жертвуют производительностью GetViewBetween()
и выигрывают производительность Count
Property.
VersionCheckImpl()
- это один из способов синхронизации свойства Count
.
Во-вторых, Mono. В коде моно GetViewBetween()
быстрее, но в методе GetCount()
:
internal override int GetCount ()
{
int count = 0;
using (var e = set.tree.GetSuffixEnumerator (lower)) {
while (e.MoveNext () && set.helper.Compare (upper, e.Current) >= 0)
++count;
}
return count;
}
Это всегда операция O (N)!