簡體   English   中英

如何凍結集合以便可以迭代它?

[英]How do I freeze a collection so that I can iterate through it?

以下代碼給了我一個例外:

var snapshot = BluetoothCapture.Instance.Snapshot();
var allowedDevice = snapshot.FirstOrDefault( _ => some_expression );

集合已修改; 枚舉操作可能無法執行。

我以為可以使用來凍結集合,以便可以對其進行迭代。 但是,我仍然遇到同樣的異常。

下面的類定義具有嘗試執行此操作的Snapshot方法:

public partial class BluetoothCapture
{
    ...

    public void Capture()
    {
        _watcher = DeviceInformation.CreateWatcher();
        _watcher.Added += (s, e) => { _devices.Add(e); };
        _watcher.Start();
    }

    public IEnumerable<DeviceInformation> Snapshot()
    {
        lock (_devices)
        {
            return _devices.AsReadOnly();
        }
    }
}

有什么建議么?

當您需要停止一個代碼塊以在多個線程中執行(停止並行執行)時,可以使用Lock。 如果多次調用Capture,那么可以,可以在上一個操作完成之前調用一次寫操作。

您可以使用ConcurrentBag。 ConcurrentBag是一個類似於對象的列表,但是它是線程安全的(沒有通用列表)。 但是,ConcurrentBag是無序集合,因此不保證有序。

如果需要一些有序列表,則可以看到此鏈接。NET中的線程安全集合

您還可以在“添加”中添加“鎖定”(而不是在獲取中)

 _watcher.Added += (s, e) => { lock(_devices){_devices.Add(e); }};

但是,如果您的應用程序運行了一段時間,那么即使Capture是運行,您也可能會遇到內存和性能問題(添加不會異步)。

lock確實是非常有用的概念,但lock是我們明智地使用它。

如果在進一步的代碼中,您不想更新snapshot引用(您從BluetoothCapture.Instance.Snapshot()獲得的集合),而只需執行一些Linq查詢以獲取過濾后的值即可執行一些邏輯。 您可以避免使用lock

這也將是有益的,因為通過不進行lock您實際上並沒有持有其他線程來執行其邏輯。 -而且,我們也不應忽視以下事實:可怕地使用lock也會導致嚴重問題,例如dead-lock

您最有可能在執行linq查詢的集合上收到此異常; 正在由其他線程更新。 (我也有這個問題)。

您可以做一件事,而不是使用collection的常規引用(從BluetoothCapture.Instance.Snapshot()獲得的引用),您可以創建一個本地列表-因為它是本地列表,其他線程不會更新它。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM