Reputation: 12892
I need to do a loop over a bunch of files and spit out log entries through a LINQ query:
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();
}
}
This query must run on a single file at a time, and the above works fine, but I need to keep appending the results of the query to an object outside of the foreach
loop. Something like this (although this doesn't work, unfortunately):
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);
}
}
How can I achieve this sort of behavior?
Not sure if it helps, my query above will return objects with (string)ID, (LogEvent)Event1180, and (LogEvent)Event1187.
Upvotes: 0
Views: 711
Reputation: 35584
You can try something like this:
Directory.EnumerateFiles(TextBoxLogDirectory.Text, "*.log")
.SelectMany(ParseFile);
where ParseFile
is defined as
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();
}
}
Or you can inline the helper function, if you want to.
This produces an IEnumerable<string>
, which you perhaps should immediately materialize with ToList
.
Edit: Oh, I see, we've got a type mismatch.
There are two ways of working around this: either you should name the anonymous type and make the function return IEnumerable<that type>
, or just inline the function content into a 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();
}
}
);
Upvotes: 2