使用循环时连接LINQ查询结果

本文关键字:LINQ 查询 结果 连接 循环 | 更新日期: 2023-09-27 18:19:03

我需要在一堆文件上做一个循环,并通过LINQ查询吐出日志条目:

foreach (string file in Directory.EnumerateFiles(TextBoxLogDirectory.Text, "*.log"))
{
    FileStream stream = new FileStream(file, FileMode.Open, FileAccess.Read, FileShare.ReadWrite | FileShare.Delete);
    using (LogReader reader = new LogReader(stream))
    {
        var events = (from x in reader.Parse().Where(y => y.IsInRange(range) && (y.EventNo == 1180 || y.EventNo == 1187) && y.GetDefaultMessageField().Contains(":Outbound/"))
                      group x by x.GetDefaultMessageField() into grouping
                      select new
                      {
                          ID = grouping.Key,
                          Event1180 = grouping.LastOrDefault(z => z.EventNo == 1180),
                          Event1187 = grouping.LastOrDefault(z => z.EventNo == 1187)
                      }).ToList();
    }
}

这个查询必须一次在一个文件上运行,上面的工作很好,但是我需要继续将查询的结果附加到foreach循环之外的对象。类似这样的内容(尽管不幸的是这不起作用):

dynamic events; // I want to append to this object outside of the loop's scope.
foreach (string file in Directory.EnumerateFiles(TextBoxLogDirectory.Text, "*.log"))
{
    FileStream stream = new FileStream(file, FileMode.Open, FileAccess.Read, FileShare.ReadWrite | FileShare.Delete);
    using (LogReader reader = new LogReader(stream))
    {
        events = (from x in reader.Parse().Where(y => y.IsInRange(range) && (y.EventNo == 1180 || y.EventNo == 1187) && y.GetDefaultMessageField().Contains(":Outbound/"))
                      group x by x.GetDefaultMessageField() into grouping
                      select new
                      {
                          ID = grouping.Key,
                          Event1180 = grouping.LastOrDefault(z => z.EventNo == 1180),
                          Event1187 = grouping.LastOrDefault(z => z.EventNo == 1187)
                      }).ToList().Concat(events);
    }
}

我怎样才能实现这种行为?

不确定是否有帮助,我上面的查询将返回具有(string)ID, (LogEvent)Event1180, and (LogEvent)Event1187.

使用循环时连接LINQ查询结果

的对象

您可以尝试这样做:

Directory.EnumerateFiles(TextBoxLogDirectory.Text, "*.log")
         .SelectMany(ParseFile);

其中ParseFile定义为

IEnumerable<string> ParseFile(string file)
{
    using (FileStream stream =
               new FileStream(file, FileMode.Open, FileAccess.Read,
                              FileShare.ReadWrite | FileShare.Delete))
    using (LogReader reader = new LogReader(stream))
    {
        return (from x in reader.Parse()
                   .Where(y => y.IsInRange(range) &&
                          (y.EventNo == 1180 || y.EventNo == 1187) &&
                          y.GetDefaultMessageField().Contains(":Outbound/"))
                group x by x.GetDefaultMessageField() into grouping
                select new
                {
                    ID = grouping.Key,
                    Event1180 = grouping.LastOrDefault(z => z.EventNo == 1180),
                    Event1187 = grouping.LastOrDefault(z => z.EventNo == 1187)
                }).ToList();
    }
}

如果需要,也可以内联helper函数。

这会产生一个IEnumerable<string>,您可能应该立即用ToList实现它。


编辑:哦,我明白了,我们有一个类型不匹配。 有两种方法可以解决这个问题:或者您应该命名匿名类型并使函数返回IEnumerable<that type>,或者只是将函数内容内联到lambda:
Directory.EnumerateFiles(TextBoxLogDirectory.Text, "*.log")
         .SelectMany(file =>
    {
        using (FileStream stream =
                   new FileStream(file, FileMode.Open, FileAccess.Read,
                                  FileShare.ReadWrite | FileShare.Delete))
        using (LogReader reader = new LogReader(stream))
        {
            return (from x in reader.Parse()
            // ...
                }).ToList();
        }
    }
);