1

I have a list of object called eventQueue in which i've stored all the event produced by a task executed in background. Now, i need to handle this list extracting specific event from it. I would like to use LINQ mostly for code readability (i wouldn't like to write multiple foreach), my problem is that i don't exactly know how to proceed. Suppose that i have multiple instance of a custom EventArgsnamed FirstEventArgs, and i want to extract a specific one from the list, doing a foreach i would write

foreach(object o in eventQueue)
{
   if( o is FirstEventArgs)
   {
       FirstEventArgs ev = o as FirstEventArgs ;
       if( ev.MyProperty == desiredValue)
       {
          // you got it 
       }
   }
}

currently i was able to write the following in LINQ

FirstEventArgs ev = eventQueue.Where(x => x.GetType() == typeof(FirstEventArgs )).SingleOrDefault() as FirstEventArgs;

my problem is. How do i modify the previous to add the condition ev.MyProperty = desiredValue in the Where if x is of type object?

Daniele Sartori
  • 1,674
  • 22
  • 38

3 Answers3

3

You can use pattern matching in your LINQ query to cast the object to your type:

FirstEventArgs ev = eventQueue.Where(x => x is FirstEventArgs fea && fea.MyProperty == desiredValue)
                              .SingleOrDefault() as FirstEventArgs;

Thanks to @Slappywag for checking that it works!

mmathis
  • 1,610
  • 18
  • 29
  • this is neat. I had no clue you could have done such thing. I'll leave the accepted answer to the other guy just because he was faster, but your answer is much more readable – Daniele Sartori Feb 14 '19 at 15:15
2

You can use an && operator and then cast to the desired type. The second half of the AND statement will only be evaluated if the first half is true, so you won't get any errors from the cast. This is known as short circuit evaluation and according to this answer (Is relying on && short-circuiting safe in .NET?) can be relied upon in C#.

FirstEventArgs ev = eventQueue.Where(x => x.GetType() == typeof(FirstEventArgs) 
                                       && ((FirstEventArgs)x).MyProperty == desiredValue)
                              .SingleOrDefault() as FirstEventArgs;
Slappywag
  • 1,143
  • 1
  • 17
  • 27
  • 2
    Does pattern matching work in LINQ queries, e.g., `eventQueue.Where(x => x is FirstEventArgs fea && fea.MyProperty == desiredValue)`? – mmathis Feb 14 '19 at 14:55
  • @mmathis I've just checked it - Yes it does, feel free to add it as an answer. It's better than mine :) – Slappywag Feb 14 '19 at 14:57
  • i was close. What i was doing wrong was to do && (FirstEventArgs)x.MyProperty == desiredValue instead of &&((FirstEventArgs)x).MyProperty == desiredValue. Thank you – Daniele Sartori Feb 14 '19 at 15:01
2

OfType lets you do a type test and throws in the cast for free:

FirstEventArgs ev = eventQueue
                     .OfType<FirstEventArgs>()
                     .SingleOrDefault(fea=>fea.MyProperty==desiredValue);

(I also moved the remaining filtering into the SingleOrDefault call because, why not?)

Yes, the other answers also work, but there's still a bit too much "mechanism" for my tastes, versus just declaring what we want.

Damien_The_Unbeliever
  • 234,701
  • 27
  • 340
  • 448