【问题标题】:Concatenating LINQ query results when using loops使用循环时连接 LINQ 查询结果
【发布时间】:2014-08-20 20:26:27
【问题描述】:

我需要对一堆文件进行循环并通过 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. 的对象

【问题讨论】:

    标签: c# .net linq linq-to-objects concat


    【解决方案1】:

    你可以试试这样的:

    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();
        }
    }
    

    如果您愿意,也可以内联辅助函数。

    这会产生一个IEnumerable&lt;string&gt;,您或许应该立即使用ToList 实现它。


    编辑:哦,我明白了,我们的类型不匹配。

    有两种解决方法:您应该命名匿名类型并让函数返回 IEnumerable&lt;that type&gt;,或者只是将函数内容内联到 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();
            }
        }
    );
    

    【讨论】:

    • 这不起作用。它抱怨“select”语句是“select new”的一部分,并出现以下错误:“错误 2 无法将类型 'System.Collections.Generic.IEnumerable' 隐式转换为 'System.Collections.Generic .IEnumerable'。存在显式转换(您是否缺少演员表?)"
    • @Alexandru:另一个重要更正:在解析器函数中添加了ToList,因为它正在关闭阅读器!
    • 是的,我现在明白了...我需要做的实际上是创建一个具有三个公共方法的类...一个字符串、一个 LogEvent 和另一个 LogEvent,它们的名称必须与我的名称匹配查询,我可以“选择新的
    • @Alexandru:是的,但是如果您将答案底部的函数内联,则可以避免它。
    • 有趣。看,有很多关于 LINQ 的东西我每天都不知道和学习。谢谢!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-09-09
    • 2013-04-10
    • 2012-03-23
    • 2012-11-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多