如何将ConcurrentQueue转换为ImmutableQueue?
如何将ConcurrentQueue转换为ImmutableQueue
这个问题我之前也碰到过!确实ConcurrentQueue不像ConcurrentDictionary那样自带ToImmutableQueue()扩展方法,不过我们有几种简单可靠的方式来实现这个转换,而且还能保证线程安全:
方法一:直接使用ImmutableQueue.CreateRange()
ImmutableQueue提供了静态方法CreateRange(),它可以接收任意IEnumerable<T>作为输入,而ConcurrentQueue正好实现了这个接口,所以我们可以直接这样写:
private readonly ConcurrentQueue<JObject> x = new ConcurrentQueue<JObject>(); public ImmutableQueue<JObject> X => ImmutableQueue.CreateRange(x);
不过要注意,直接遍历ConcurrentQueue的时候,如果其他线程同时修改队列,遍历结果可能不是原子性的快照。如果需要获取转换瞬间的完整队列快照,我们可以结合ConcurrentQueue的ToArray()方法——这个方法是线程安全的,会返回调用时刻队列的完整副本:
private readonly ConcurrentQueue<JObject> x = new ConcurrentQueue<JObject>(); public ImmutableQueue<JObject> X { get { // 先获取线程安全的快照数组,再转换为不可变队列 var queueSnapshot = x.ToArray(); return ImmutableQueue.CreateRange(queueSnapshot); } }
方法二:封装成自定义扩展方法
如果需要像ToImmutableDictionary()那样方便地调用,我们可以自己写一个扩展方法,把上面的逻辑封装起来:
public static class ConcurrentQueueExtensions { public static ImmutableQueue<T> ToImmutableQueue<T>(this ConcurrentQueue<T> queue) { if (queue == null) throw new ArgumentNullException(nameof(queue)); // 基于线程安全的快照生成不可变队列 return ImmutableQueue.CreateRange(queue.ToArray()); } }
之后就可以像你最初期望的那样调用了:
private readonly ConcurrentQueue<JObject> x = new ConcurrentQueue<JObject>(); public ImmutableQueue<JObject> X => x.ToImmutableQueue();
为什么没有内置的ToImmutableQueue()?
其实原因很简单:ConcurrentDictionary的ToImmutableDictionary()是专门针对字典的线程安全转换优化过的,而ConcurrentQueue的转换可以通过现有API组合实现,所以.NET团队没有专门提供这个扩展方法,但上面的方案完全可以满足需求。
内容的提问来源于stack exchange,提问作者bsky
相关产品推荐
相关产品推荐

