Блог переехал. Актуальная версия поста находится по адресу: http://aakinshin.net/ru/blog/dotnet/listforeach-net-45/.
Продолжим обсуждать тему изменения коллекции внутри цикла foreach
. Следующий код
var list = new List<int> { 1, 2 }; foreach (var i in list) { if (i == 1) list.Add(3); Console.WriteLine(i); }выбросит
InvalidOperationException
. А как думаете, что случится при выполнении цикла через List<T>.ForEach?
var list = new List<int> { 1, 2 }; list.ForEach(i => { if (i == 1) list.Add(3); Console.WriteLine(i); });
Правильный ответ: зависит. Ранее (.NET 4.0) данный код замечательно отрабатывал и выводил 1 2 3
. Это было не очень хорошо. Поэтому в .NET 4.5 поведение поменялось, ForEach
начал бросать InvalidOperationException
для случая, если кто-то внутри цикла менял коллекцию:
public void ForEach(Action<T> action) { if( action == null) { ThrowHelper.ThrowArgumentNullException(ExceptionArgument.match); } Contract.EndContractBlock(); int version = _version; for(int i = 0 ; i < _size; i++) { if (version != _version && BinaryCompatibility.TargetsAtLeast_Desktop_V4_5) { break; } action(_items[i]); } if (version != _version && BinaryCompatibility.TargetsAtLeast_Desktop_V4_5) ThrowHelper.ThrowInvalidOperationException( ExceptionResource.InvalidOperation_EnumFailedVersion); }
Что касается Mono, то в нём никаких исключение не бросается (даже в последнем стабильном на текущий момент Mono 3.10). Когда я узнал, что в Mono 3.10 всё плохо, то очень расстроился. А потом пошёл и завёл баг-репорт. Вскоре баг был исправлен.
А в старых версий (например, 2.10) был баг, в результате которого исключение не происходило даже внутри обычного foreach
, если коллекцию менять через индексатор (ideone):
using System; using System.Collections.Generic; namespace test { public class test { public static void Main() { Listx = new List (); x.Add(1); x.Add(4); x.Add(9); foreach(int i in x){ x[2] = 3; } foreach(int i in x){ System.Console.WriteLine(i); } } } } Actual Results (Mono 2.10): 1 4 3
Ссылки по теме
- .NET Web Development and Tools Blog: All about : All about <httpRuntime targetFramework>
- .NET Framework Blog: .NET Framework 4.5 – Off to a great start
- ItDepends.NET: ListForEach
- MSDN: InvalidOperationException
- Mono Bug 699182: Modifications to a Collection via indexer during foreach should throw InvalidOperationException
- Mono Bug 24775: List.ForEach does not throw InvalidOperationException when collection was modified
Комментариев нет:
Отправить комментарий