如何将项目添加到集合中,同时对其进行过滤?

时间:2015-10-30 08:25:40

标签: c# multithreading collections

我有一组日志事件。我让用户能够过滤掉不同的日志级别。在该过滤过程中,如果添加了新的日志事件,则会引发异常。我可以在过滤时锁定集合,但这意味着任何新的日志事件都不会以正确的顺序添加,或者根本不添加(?)。

过滤方法:

//Filters and returns a list of filtered log events
    private IEnumerable<LogEvent> FilterLogEvents()
    {
        return (from x in LogEvents
                where ((ViewDebugLogs == true) ? x.Level == "Debug" : false)
                || ((ViewErrorLogs == true) ? x.Level == "Error" : false)
                || ((ViewInfoLogs == true) ? x.Level == "Info" : false)
                select x);
    }

如果我只是返回一个列表,如果它在查询中期就会发生同样的事情。

如何在添加到集合的同时使用它?这里主要关注的是确保将日志事件以正确的顺序添加到集合中(如果它是在过滤器中添加的话)。因此,如果我无法同时添加日志事件,我可以以某种方式将它们排队并在之后正确插入它们吗?

2 个答案:

答案 0 :(得分:0)

不,枚举时无法修改集合。您可以复制集合,枚举副本,并在枚举期间修改原始集合。

//the following example throws an exception
var numbers = GetTheNumbers();
foreach(var number in numbers)
{
    numbers.Add(1);   //exception thrown
}

//copy the collection first
var numbers = GetTheNumbers();
var copy = numbers.ToArray();
foreach(var number in copy)
{
    numbers.Add(1);  //safe
}

答案 1 :(得分:0)

您可以在向其添加项目的同时迭代某些并发集合。一个这样的集合是ConcurrentQueue<T>,如果满足以下条件,我认为它可能适用于日志:

  • 您只想在日志末尾添加项目。
  • 你永远不需要一次性清空它。 (而不是清空队列,你必须创建一个新的空队列,或者你必须循环调用TryDequeue()直到它为空。)

请注意,当您迭代ConcurrentQueue<T>时,似乎在迭代开始时读取计数而在迭代期间不会更新,因此如果在您重复迭代时添加了新项目,您将赢得& #39;看到它们(但添加的项目不会导致异常)。

这是一个演示程序:

using System;
using System.Collections.Concurrent;
using System.Threading;
using System.Threading.Tasks;

namespace Demo
{
    internal class Program
    {
        public static void Main()
        {
            var queue = new ConcurrentQueue<int>();

            Task.Run(() =>
            {
                for (int i = 0; i < 1000; ++i)
                {
                    queue.Enqueue(i);
                    Thread.Sleep(1);
                }
            });

            Thread.Sleep(100);
            Console.WriteLine($"Count before loop: {queue.Count}");

            foreach (var i in queue)
                Console.WriteLine($"{i}, n={queue.Count}");
        }
    }
}