Bộ sưu tập đã được sửa đổi; phép liệt kê có thể không thực thi


911

Tôi không thể đi đến tận cùng của lỗi này, bởi vì khi trình gỡ lỗi được đính kèm, nó dường như không xảy ra. Dưới đây là mã.

Đây là một máy chủ WCF trong một dịch vụ Windows. Phương thức NotifySubscribe được dịch vụ gọi bất cứ khi nào có sự kiện dữ liệu (theo các khoảng thời gian ngẫu nhiên, nhưng không thường xuyên - khoảng 800 lần mỗi ngày).

Khi ứng dụng khách Windows Forms đăng ký, ID thuê bao sẽ được thêm vào từ điển của người đăng ký và khi khách hàng hủy đăng ký, nó sẽ bị xóa khỏi từ điển. Lỗi xảy ra khi (hoặc sau) một khách hàng hủy đăng ký. Có vẻ như lần sau khi phương thức NotifySubscribeers () được gọi, vòng lặp foreach () không thành công với lỗi trong dòng chủ đề. Phương thức ghi lỗi vào nhật ký ứng dụng như trong đoạn mã dưới đây. Khi trình gỡ lỗi được đính kèm và máy khách hủy đăng ký, mã sẽ thực thi tốt.

Bạn có thấy một vấn đề với mã này? Tôi có cần làm cho chủ đề từ điển an toàn không?

[ServiceBehavior(InstanceContextMode=InstanceContextMode.Single)]
public class SubscriptionServer : ISubscriptionServer
{
    private static IDictionary<Guid, Subscriber> subscribers;

    public SubscriptionServer()
    {            
        subscribers = new Dictionary<Guid, Subscriber>();
    }

    public void NotifySubscribers(DataRecord sr)
    {
        foreach(Subscriber s in subscribers.Values)
        {
            try
            {
                s.Callback.SignalData(sr);
            }
            catch (Exception e)
            {
                DCS.WriteToApplicationLog(e.Message, 
                  System.Diagnostics.EventLogEntryType.Error);

                UnsubscribeEvent(s.ClientId);
            }
        }
    }


    public Guid SubscribeEvent(string clientDescription)
    {
        Subscriber subscriber = new Subscriber();
        subscriber.Callback = OperationContext.Current.
                GetCallbackChannel<IDCSCallback>();

        subscribers.Add(subscriber.ClientId, subscriber);

        return subscriber.ClientId;
    }


    public void UnsubscribeEvent(Guid clientId)
    {
        try
        {
            subscribers.Remove(clientId);
        }
        catch(Exception e)
        {
            System.Diagnostics.Debug.WriteLine("Unsubscribe Error " + 
                    e.Message);
        }
    }
}

trong trường hợp của tôi, đó là một hiệu ứng tài sản thế chấp vì tôi đang sử dụng một vài .Include ("bảng") đã được sửa đổi trong quá trình - không rõ ràng khi đọc mã. tuy nhiên tôi đã may mắn rằng những Bao gồm đó không cần thiết (vâng! mã cũ, không rõ ràng) và tôi đã giải quyết vấn đề của mình bằng cách xóa chúng
Adi

Câu trả lời:


1631

Điều có thể xảy ra là SignalData đang gián tiếp thay đổi từ điển người đăng ký dưới mui xe trong vòng lặp và dẫn đến thông báo đó. Bạn có thể xác minh điều này bằng cách thay đổi

foreach(Subscriber s in subscribers.Values)

Đến

foreach(Subscriber s in subscribers.Values.ToList())

Nếu tôi đúng, vấn đề sẽ biến mất

Gọi subscribers.Values.ToList()sao chép các giá trị của subscribers.Valuesmột danh sách riêng khi bắt đầu foreach. Không có gì khác có quyền truy cập vào danh sách này (thậm chí nó không có tên biến!), Vì vậy không có gì có thể sửa đổi nó trong vòng lặp.


14
BTW .ToList () có trong System.Core dll không tương thích với các ứng dụng .NET 2.0. Vì vậy, bạn có thể cần phải thay đổi ứng dụng mục tiêu của mình thành .Net 3.5
mishal153

60
Tôi không hiểu tại sao bạn lại thực hiện một ToList và tại sao điều đó khắc phục mọi thứ
positiveGuy

204
@CoffeeAddict: Vấn đề là subscribers.Valuesđang được sửa đổi trong foreachvòng lặp. Gọi subscribers.Values.ToList()sao chép các giá trị của subscribers.Valuesmột danh sách riêng khi bắt đầu foreach. Không có gì khác có quyền truy cập vào danh sách này (thậm chí nó không có tên biến!) , Vì vậy không có gì có thể sửa đổi nó trong vòng lặp.
BlueRaja - Daniel Pflughoeft

31
Lưu ý rằng ToListcũng có thể ném nếu bộ sưu tập đã được sửa đổi trong khi ToListđang thực thi.
Sriram Sakth Xoay

16
Tôi khá chắc chắn nghĩ rằng không khắc phục được vấn đề, nhưng chỉ khiến nó khó tái tạo hơn. ToListkhông phải là một hoạt động nguyên tử. Có gì thậm chí hài hước, ToListbascially làm riêng của mình foreachtrong nội bộ để sao chép các mục vào một trường hợp danh sách mới, có nghĩa là bạn cố định một foreachvấn đề bằng cách thêm một bổ sung (mặc dù nhanh hơn) foreachlặp đi lặp lại.
Groo

113

Khi người đăng ký hủy đăng ký, bạn sẽ thay đổi nội dung của bộ sưu tập Người đăng ký trong quá trình liệt kê.

Có một số cách để khắc phục điều này, một cách thay đổi vòng lặp for để sử dụng một cách rõ ràng .ToList():

public void NotifySubscribers(DataRecord sr)  
{
    foreach(Subscriber s in subscribers.Values.ToList())
    {
                                              ^^^^^^^^^  
        ...

64

Theo tôi, một cách hiệu quả hơn là có một danh sách khác mà bạn tuyên bố rằng bạn đặt bất cứ thứ gì "bị loại bỏ" vào. Sau đó, sau khi bạn hoàn thành vòng lặp chính của mình (không có .ToList ()), bạn thực hiện một vòng lặp khác trong danh sách "sẽ bị xóa", xóa từng mục khi nó xảy ra. Vì vậy, trong lớp học của bạn, bạn thêm:

private List<Guid> toBeRemoved = new List<Guid>();

Sau đó, bạn thay đổi nó thành:

public void NotifySubscribers(DataRecord sr)
{
    toBeRemoved.Clear();

    ...your unchanged code skipped...

   foreach ( Guid clientId in toBeRemoved )
   {
        try
        {
            subscribers.Remove(clientId);
        }
        catch(Exception e)
        {
            System.Diagnostics.Debug.WriteLine("Unsubscribe Error " + 
                e.Message);
        }
   }
}

...your unchanged code skipped...

public void UnsubscribeEvent(Guid clientId)
{
    toBeRemoved.Add( clientId );
}

Điều này sẽ không chỉ giải quyết vấn đề của bạn, nó sẽ ngăn bạn tiếp tục tạo một danh sách từ từ điển của bạn, rất tốn kém nếu có nhiều người đăng ký trong đó. Giả sử danh sách các thuê bao bị xóa trên bất kỳ lần lặp cụ thể nào thấp hơn tổng số trong danh sách, việc này sẽ nhanh hơn. Nhưng tất nhiên hãy thoải mái cấu hình nó để chắc chắn đó là trường hợp nếu có bất kỳ nghi ngờ nào trong tình huống sử dụng cụ thể của bạn.


9
Tôi hy vọng điều này sẽ đáng xem xét nếu bạn có một bộ sưu tập lớn hơn. Nếu nó nhỏ, có lẽ tôi chỉ cần ToList và tiếp tục.
Karl Kieninger

42

Bạn cũng có thể khóa từ điển người đăng ký để tránh bị sửa đổi bất cứ khi nào nó bị lặp:

 lock (subscribers)
 {
         foreach (var subscriber in subscribers)
         {
               //do something
         }
 }

2
Đó có phải là một ví dụ hoàn chỉnh? Tôi có một lớp (_dixi obj bên dưới) có chứa một từ điển chung <string, int> có tên MarkerFrequencies, nhưng làm điều này không giải quyết được ngay sự cố: lock (_dipedia.MarkerFrequencies) {foreach (KeyValuePair <string, int> _dipedia.MarkerFrequencies) {...}}
Jon Coombs

4
@JCoombs có thể bạn đang sửa đổi, có thể chỉ định lại MarkerFrequenciestừ điển bên trong khóa, có nghĩa là phiên bản gốc không còn bị khóa. Ngoài ra, hãy thử sử dụng forthay vì a foreach, Xem cái nàycái này . Hãy cho tôi biết nếu điều đó giải quyết nó.
Mohammad Sepahvand

1
Chà, cuối cùng tôi cũng đã khắc phục được lỗi này và những lời khuyên này rất hữu ích - cảm ơn! Tập dữ liệu của tôi rất nhỏ và thao tác này chỉ là một bản cập nhật hiển thị UI, vì vậy việc lặp lại qua một bản sao có vẻ tốt nhất. (Tôi cũng đã thử nghiệm sử dụng thay vì foreach sau khi khóa MarkerFrequencies trong cả hai luồng. Điều này đã ngăn chặn sự cố nhưng dường như yêu cầu công việc sửa lỗi thêm. Và nó giới thiệu phức tạp hơn. Lý do duy nhất của tôi để có hai luồng ở đây là cho phép người dùng hủy Nhân tiện, một thao tác. Giao diện người dùng không trực tiếp sửa đổi dữ liệu đó.)
Jon Coombs

9
Vấn đề là, đối với các ứng dụng lớn, các khóa có thể là một điểm nhấn hiệu năng lớn - tốt hơn hết là sử dụng một bộ sưu tập trong System.Collections.Concurrentkhông gian tên.
BrainSlugs83

28

Tại sao lỗi này?

Nói chung, các bộ sưu tập .Net không hỗ trợ việc liệt kê và sửa đổi cùng một lúc. Nếu bạn cố gắng sửa đổi danh sách bộ sưu tập trong quá trình liệt kê, nó sẽ đưa ra một ngoại lệ. Vì vậy, vấn đề đằng sau lỗi này là, chúng tôi không thể sửa đổi danh sách / từ điển trong khi chúng tôi đang lặp lại như vậy.

Một trong những giải pháp

Nếu chúng ta lặp lại một từ điển bằng cách sử dụng danh sách các khóa của nó, song song chúng ta có thể sửa đổi đối tượng từ điển, vì chúng ta đang lặp qua bộ sưu tập khóa chứ không phải từ điển (và lặp lại bộ sưu tập khóa của nó).

Thí dụ

//get key collection from dictionary into a list to loop through
List<int> keys = new List<int>(Dictionary.Keys);

// iterating key collection using a simple for-each loop
foreach (int key in keys)
{
  // Now we can perform any modification with values of the dictionary.
  Dictionary[key] = Dictionary[key] - 1;
}

Đây là một bài viết trên blog về giải pháp này.

Và cho một lần lặn sâu trong StackOverflow: Tại sao lỗi này xảy ra?


Cảm ơn bạn! Một lời giải thích rõ ràng về lý do tại sao nó xảy ra và ngay lập tức cho tôi cách để giải quyết điều này trong ứng dụng của tôi.
Kim Crosser

5

Trên thực tế, vấn đề đối với tôi là bạn đang loại bỏ các yếu tố khỏi danh sách và mong muốn tiếp tục đọc danh sách như thể không có gì xảy ra.

Những gì bạn thực sự cần làm là bắt đầu từ cuối và trở lại bắt đầu. Ngay cả khi bạn loại bỏ các yếu tố khỏi danh sách, bạn sẽ có thể tiếp tục đọc nó.


Tôi không thấy làm thế nào mà làm cho bất kỳ sự khác biệt? Nếu bạn loại bỏ một phần tử ở giữa danh sách, nó vẫn sẽ xuất hiện lỗi vì mục mà nó đang cố truy cập không thể tìm thấy?
Zapnologica

4
@Zapnologica sự khác biệt là - bạn sẽ không liệt kê danh sách - thay vì thực hiện cho / mỗi, bạn sẽ thực hiện một / tiếp theo và truy cập nó theo số nguyên - bạn hoàn toàn có thể sửa đổi danh sách a trong một vòng lặp for / next, nhưng không bao giờ trong vòng lặp for / mỗi vòng lặp (vì for / mỗi liệt kê ) - bạn cũng có thể thực hiện chuyển tiếp trong vòng lặp for / next, miễn là bạn có thêm logic để điều chỉnh bộ đếm của mình, v.v.
BrainSlugs83

4

UnlimitedOperationException- Một UnlimitedOperationException đã xảy ra. Nó báo cáo một "bộ sưu tập đã được sửa đổi" trong một vòng lặp foreach

Sử dụng câu lệnh break, Sau khi đối tượng được gỡ bỏ.

Ví dụ:

ArrayList list = new ArrayList(); 

foreach (var item in list)
{
    if(condition)
    {
        list.remove(item);
        break;
    }
}

Giải pháp tốt và đơn giản nếu bạn biết danh sách của mình có nhiều nhất một mục cần phải xóa.
Tawab Wakil

3

Tôi đã có cùng một vấn đề, và nó đã được giải quyết khi tôi sử dụng một forvòng lặp thay vì foreach.

// foreach (var item in itemsToBeLast)
for (int i = 0; i < itemsToBeLast.Count; i++)
{
    var matchingItem = itemsToBeLast.FirstOrDefault(item => item.Detach);

   if (matchingItem != null)
   {
      itemsToBeLast.Remove(matchingItem);
      continue;
   }
   allItems.Add(itemsToBeLast[i]);// (attachDetachItem);
}

11
Mã này sai và sẽ bỏ qua một số mục trong bộ sưu tập nếu bất kỳ phần tử nào sẽ bị xóa. Ví dụ: bạn có var Array = ["a", "b", "c"] và trong lần lặp đầu tiên (i = 0) bạn xóa phần tử ở vị trí 0 (phần tử "a"). Sau đó, tất cả các phần tử mảng sẽ di chuyển một vị trí lên và mảng sẽ là ["b", "c"]. Vì vậy, trong lần lặp tiếp theo (i = 1), bạn sẽ kiểm tra phần tử ở vị trí 1 sẽ là "c" chứ không phải "b". Cái này sai. Để khắc phục điều đó, bạn phải di chuyển từ dưới lên trên cùng
Muffars Ozols

3

Được rồi, điều giúp tôi là lặp đi lặp lại. Tôi đã cố xóa một mục trong danh sách nhưng lặp đi lặp lại và nó làm hỏng vòng lặp vì mục đó không còn tồn tại nữa:

for (int x = myList.Count - 1; x > -1; x--)
                        {

                            myList.RemoveAt(x);

                        }

2

Tôi đã thấy nhiều lựa chọn cho việc này nhưng với tôi đây là lựa chọn tốt nhất.

ListItemCollection collection = new ListItemCollection();
        foreach (ListItem item in ListBox1.Items)
        {
            if (item.Selected)
                collection.Add(item);
        }

Sau đó, chỉ cần lặp qua bộ sưu tập.

Xin lưu ý rằng ListItemCollection có thể chứa các bản sao. Theo mặc định, không có gì ngăn chặn các bản sao được thêm vào bộ sưu tập. Để tránh trùng lặp, bạn có thể làm điều này:

ListItemCollection collection = new ListItemCollection();
            foreach (ListItem item in ListBox1.Items)
            {
                if (item.Selected && !collection.Contains(item))
                    collection.Add(item);
            }

Làm thế nào mã này sẽ ngăn chặn các bản sao được nhập vào cơ sở dữ liệu. Tôi đã viết một cái gì đó tương tự và khi tôi thêm người dùng mới từ hộp danh sách, nếu tôi vô tình giữ một lựa chọn đã có trong danh sách, nó sẽ tạo ra một mục trùng lặp. Bạn có gợi ý nào @Mike không?
Jamie

1

Câu trả lời được chấp nhận là không chính xác và không chính xác trong trường hợp xấu nhất. Nếu thay đổi được thực hiện trong thời gianToList() , bạn vẫn có thể gặp lỗi. Bên cạnh đó lock, hiệu suất và an toàn luồng cần được xem xét nếu bạn có một thành viên công cộng, một giải pháp thích hợp có thể là sử dụng các loại không thay đổi .

Nói chung, một loại không thay đổi có nghĩa là bạn không thể thay đổi trạng thái của nó một khi được tạo. Vì vậy, mã của bạn sẽ trông như:

public class SubscriptionServer : ISubscriptionServer
{
    private static ImmutableDictionary<Guid, Subscriber> subscribers = ImmutableDictionary<Guid, Subscriber>.Empty;
    public void SubscribeEvent(string id)
    {
        subscribers = subscribers.Add(Guid.NewGuid(), new Subscriber());
    }
    public void NotifyEvent()
    {
        foreach(var sub in subscribers.Values)
        {
            //.....This is always safe
        }
    }
    //.........
}

Điều này có thể đặc biệt hữu ích nếu bạn có một thành viên công cộng. Các lớp khác luôn có thể foreachthuộc các loại bất biến mà không phải lo lắng về việc bộ sưu tập bị sửa đổi.


1

Đây là một kịch bản cụ thể đảm bảo một cách tiếp cận chuyên ngành:

  1. Các Dictionaryđược liệt kê thường xuyên.
  2. Việc Dictionarysửa đổi không thường xuyên.

Trong kịch bản này, việc tạo một bản sao của Dictionary(hoặc Dictionary.Values) trước mỗi phép liệt kê có thể khá tốn kém. Ý tưởng của tôi về việc giải quyết vấn đề này là sử dụng lại cùng một bản sao được lưu trong bộ nhớ cache trong nhiều bảng liệt kê và xem một IEnumeratorbản gốc Dictionaryđể biết các trường hợp ngoại lệ. Điều tra viên sẽ được lưu trữ cùng với dữ liệu được sao chép và được thẩm vấn trước khi bắt đầu một bảng liệt kê mới. Trong trường hợp ngoại lệ, bản sao được lưu trong bộ nhớ cache sẽ bị loại bỏ và một bản sao mới sẽ được tạo. Đây là cách tôi thực hiện ý tưởng này:

using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;

public class EnumerableSnapshot<T> : IEnumerable<T>, IDisposable
{
    private IEnumerable<T> _source;
    private IEnumerator<T> _enumerator;
    private ReadOnlyCollection<T> _cached;

    public EnumerableSnapshot(IEnumerable<T> source)
    {
        _source = source ?? throw new ArgumentNullException(nameof(source));
    }

    public IEnumerator<T> GetEnumerator()
    {
        if (_source == null) throw new ObjectDisposedException(this.GetType().Name);
        if (_enumerator == null)
        {
            _enumerator = _source.GetEnumerator();
            _cached = new ReadOnlyCollection<T>(_source.ToArray());
        }
        else
        {
            var modified = false;
            if (_source is ICollection collection) // C# 7 syntax
            {
                modified = _cached.Count != collection.Count;
            }
            if (!modified)
            {
                try
                {
                    _enumerator.MoveNext();
                }
                catch (InvalidOperationException)
                {
                    modified = true;
                }
            }
            if (modified)
            {
                _enumerator.Dispose();
                _enumerator = _source.GetEnumerator();
                _cached = new ReadOnlyCollection<T>(_source.ToArray());
            }
        }
        return _cached.GetEnumerator();
    }

    public void Dispose()
    {
        _enumerator?.Dispose();
        _enumerator = null;
        _cached = null;
        _source = null;
    }

    IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
}

public static class EnumerableSnapshotExtensions
{
    public static EnumerableSnapshot<T> ToEnumerableSnapshot<T>(
        this IEnumerable<T> source) => new EnumerableSnapshot<T>(source);
}

Ví dụ sử dụng:

private static IDictionary<Guid, Subscriber> _subscribers;
private static EnumerableSnapshot<Subscriber> _subscribersSnapshot;

//...(in the constructor)
_subscribers = new Dictionary<Guid, Subscriber>();
_subscribersSnapshot = _subscribers.Values.ToEnumerableSnapshot();

// ...(elsewere)
foreach (var subscriber in _subscribersSnapshot)
{
    //...
}

Thật không may, ý tưởng này hiện không thể được sử dụng với lớp Dictionarytrong .NET Core 3.0, vì lớp này không ném Bộ sưu tập đã được sửa đổi ngoại lệ khi liệt kê và các phương thức RemoveClearđược gọi. Tất cả các container khác tôi đã kiểm tra đang hành xử nhất quán. Tôi đã kiểm tra một cách hệ thống các lớp: List<T>, Collection<T>, ObservableCollection<T>, HashSet<T>, SortedSet<T>, Dictionary<T,V>SortedDictionary<T,V>. Chỉ có hai phương thức đã nói Dictionaryở trên trong .NET Core không làm mất hiệu lực liệt kê.


Cập nhật: Tôi đã khắc phục vấn đề trên bằng cách so sánh độ dài của bộ nhớ cache và bộ sưu tập gốc. Khắc phục sự cố này giả định rằng từ điển sẽ được chuyển trực tiếp dưới dạng đối số cho hàm EnumerableSnapshottạo của nó và danh tính của nó sẽ không bị ẩn bởi (ví dụ) một phép chiếu như : dictionary.Select(e => e).ΤοEnumerableSnapshot().


Quan trọng: Các lớp trên không phải là chủ đề an toàn. Nó được dự định sẽ được sử dụng từ mã chạy riêng trong một luồng.


0

Bạn có thể sao chép đối tượng từ điển thuê bao sang cùng một loại đối tượng từ điển tạm thời và sau đó lặp lại đối tượng từ điển tạm thời bằng vòng lặp foreach.


(Bài đăng này dường như không cung cấp câu trả lời chất lượng cho câu hỏi. Vui lòng chỉnh sửa câu trả lời của bạn và chỉ đăng bài dưới dạng nhận xét cho câu hỏi).
sɐunıɔ qɐp

0

Vì vậy, một cách khác để giải quyết vấn đề này là thay vì loại bỏ các yếu tố tạo từ điển mới và chỉ thêm các yếu tố bạn không muốn xóa sau đó thay thế từ điển gốc bằng từ điển mới. Tôi không nghĩ rằng đây là quá nhiều vấn đề hiệu quả bởi vì nó không làm tăng số lần bạn lặp lại trên cấu trúc.


0

Có một liên kết nơi nó được xây dựng rất tốt và giải pháp cũng được đưa ra. Hãy thử nếu bạn có giải pháp thích hợp xin vui lòng gửi ở đây để người khác có thể hiểu. Đưa ra giải pháp là ok sau đó thích bài viết để người khác có thể thử các giải pháp này.

cho bạn tham khảo liên kết ban đầu: - https://bensonxion.wordpress.com/2012/05/07/serializing-an-ienumerable-produces-collection-was-modified-enumutions-operation-may-not-execute/

Khi chúng tôi sử dụng các lớp Tuần tự hóa .Net để tuần tự hóa một đối tượng trong đó định nghĩa của nó chứa một kiểu Có thể đếm được, tức là bộ sưu tập, bạn sẽ dễ dàng nhận được UnlimitedOperationException nói rằng "Bộ sưu tập đã được sửa đổi; hoạt động liệt kê có thể không thực thi" trong đó mã hóa của bạn nằm trong các kịch bản đa luồng. Nguyên nhân dưới cùng là các lớp tuần tự hóa sẽ lặp qua bộ sưu tập thông qua bộ liệt kê, do đó, vấn đề là cố gắng lặp qua bộ sưu tập trong khi sửa đổi nó.

Giải pháp đầu tiên, chúng ta chỉ cần sử dụng khóa như một giải pháp đồng bộ hóa để đảm bảo rằng hoạt động cho đối tượng List chỉ có thể được thực thi từ một luồng tại một thời điểm. Rõ ràng, bạn sẽ nhận được hình phạt hiệu suất mà nếu bạn muốn tuần tự hóa một bộ sưu tập của đối tượng đó, thì đối với mỗi đối tượng đó, khóa sẽ được áp dụng.

Chà, .Net 4.0 giúp xử lý các tình huống đa luồng tiện dụng. đối với vấn đề trường Bộ sưu tập tuần tự hóa này, tôi thấy rằng chúng ta chỉ có thể hưởng lợi từ lớp ConcurrencyQueue (Kiểm tra MSDN), đây là một bộ sưu tập theo chủ đề và FIFO an toàn và làm cho mã không bị khóa.

Sử dụng lớp này, để đơn giản, những thứ bạn cần sửa đổi cho mã của bạn đang thay thế loại Bộ sưu tập bằng nó, hãy sử dụng Enqueue để thêm một phần tử vào cuối ConcurrencyQueue, xóa các mã khóa đó. Hoặc, nếu kịch bản bạn đang thực hiện yêu cầu các công cụ thu thập như Danh sách, bạn sẽ cần thêm một vài mã để điều chỉnh ConcurrencyQueue vào các trường của bạn.

BTW, ConcurrencyQueue không có phương thức Clear do thuật toán cơ bản không cho phép xóa nguyên bản bộ sưu tập. Vì vậy, bạn phải tự làm điều đó, cách nhanh nhất là tạo lại một concienQueue trống mới để thay thế.


-1

Cá nhân tôi đã chạy qua mã này gần đây trong mã không quen thuộc, nơi nó nằm trong một dbcontext mở với .Remove (mục) của Linq. Tôi đã có một thời gian để xác định lỗi gỡ lỗi vì (các) mục đã bị xóa trong lần lặp đầu tiên và nếu tôi cố gắng lùi lại và bước lại, bộ sưu tập trống rỗng, vì tôi ở trong cùng một bối cảnh!

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.