C#’ta “Collection Was Modified; Enumeration Operation May Not Execute.” Hatası ve Çözümü

Merhaba,

Yazılım dünyasının temeli ve prosedürel programlamanın has elemanlarından biri olan döngü yapıları üzerinde yapılan çalışmalarda farklı olası hatalar almanız gayet normal bir durumdur. Bu hataların onlarca farklı sebebi olabilmekle beraber, döngü kalıbının başlangıç olarak belirlediği temel değerlerle iterasyon sürecindeki değişikliklerin birbirlerine tezatlık çıkarmasından kaynaklanabilmeside muhtemeldir. İşte bizde bu yazımızda buna benzer bir durumdan kaynaklanan hata üzerine odaklanacak ve çözüm yolu sunacağız.

Hiç vakit kaybetmeden aşağıdaki örnek kod bloklarını inceleyelim ve aldıkları hata üzerine konuşalım.

            List<int> Sayilar = new List<int> { 1, 3, 5, 7, 9, 11, 13, 17 };
            Sayilar.ForEach(s => Sayilar.Remove(s));
            List<int> Sayilar = new List<int> { 1, 3, 5, 7, 9, 11, 13, 17 };
            foreach (var sayi in Sayilar)
                Sayilar.Remove(sayi);

Bu iki örnek kodumuzda maksadımız foreach döngüsünün kullanım varyasyonlarını gözler önüne getirmektir. Eğer ki bir foreach döngüsünü, döngü sonlanmadan bağlı olduğu koleksiyon içerisinden veri silerek kullanmaya çalışırsak konumuz olan hatayla karşılaşmamız oldukça muhtemeldir.

Aldığımız hata metinsel olarak aşağıdaki gibidir.

System.InvalidOperationException: ‘Collection was modified; enumeration operation may not execute.’

Bu hata biraz yukarıda bahsettiğim gibi foreach döngüsünün kullandığı koleksiyonun içeriği değiştiğinden dolayı işleme devam edilememesinin bir tezahürüdür.

Bu hatadan kurtulmanın bir kaç farklı, algoritmik temellere dayanan yolları vardır. Şimdi gelin bu yolları inceleyelim.

1. Yol
foreach değil, for yahut diğer prosedürel döngüleri kullanmanız hatayı ortadan kaldıracaktır.

            List<int> Sayilar = new List<int> { 1, 3, 5, 7, 9, 11, 13, 17 };
            for (int i = 0; i < Sayilar.Count; i++)
                if(Sayilar[i] == 3)
                Sayilar.Remove(Sayilar[i]);

2. Yol
2. yol olarak aşağıdaki gibi algoritmik çalışma yapmamız yeterli olacaktır. Burada foreach döngüsünün kullandığı koleksiyondan, asıl işlem yapılacak koleksiyon soyutlandırılmıştır.

            List<int> Sayilar = new List<int> { 1, 3, 5, 7, 9, 11, 13, 17 };
            List<int> SilinecekSayilar = new List<int>() { 1, 3, 5, 7 };
            SilinecekSayilar.ForEach(s =>
            {
                if (Sayilar.Contains(s))
                    Sayilar.Remove(s);
            });

Evet… Anlayacağınız foreach döngülerinde kullanılan kaynak koleksiyon yapılarının içerikleri oldukça önem arz etmektedir. Bir iteratör mantığıyla çalışan foreach döngüsü kaynağındaki değişim esnasında iterasyondaki devamlılığı getirmekte sorunlar yaşamakta ve bu hatayı fırlatmaktadır.

Sonraki yazılarımda görüşmek üzere…
Şimdilik hoşçakalın…
İyi çalışmalar…

Bunlar da hoşunuza gidebilir...

3 Cevaplar

  1. Buğra dedi ki:

    Teşekkür ederim çok açıklayıcı bir bilgi yazmışsınız.

  2. ramazan dedi ki:

    Merhaba hocam. Web siteme login olan kullanıcının claim’lerini silmeye çalıştığımda aynı hatayı aldım ve endpointim yine zengin içerikli blogunuz oldu. 🙂 Hatayı önlemek amacıyla verdiğiniz iki yöntemi de denedim ancak aynı hatayı almaya devam ediyorum. Kullanıcı kendi bilgilerini update ettiğinde mecvut claimlerini silip güncel bilgilerine göre tekrar claim yaratmaya çalışıyorum ancak claimleri üzerinde iterasyonla silme işlemini başaramadım. Bi öneriniz olur mu? Kod görüntüsü burada: https://imgyukle.com/i/kod.ELwffI Teşekkürler. .

    • Gençay dedi ki:

      Merhaba,

      Attığın görselde “claimList” referansı ile “user.Claims” özelliğinin her ikiside aynı nesneyi göstermektedir. Dolayısıyla foreach iterasyonunun kaynağı değiştirilmeye çalışıldığından dolayı hata alınmaktadır. Nacizane önerim, “user.Claims” koleksiyonunu bir şekilde başka bir koleksiyona kopyalaman(aman dikkat, farklı bir referansla işaretlemen değil) ve ardından o kopya üzerinde foreach ile çalışman.

      Kolay gelsin.

Bir cevap yazın

E-posta hesabınız yayımlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir

*