0

I found some duplicate code today and would like to reduce it to one method. In order to do it, I'd like to inject something more abstract into the lambda here:

public IEnumerable<AbstractFoo> GetMatchingFoos()
{
     return IEnumerable<AbstractFoo> exactMatchFoo = exactMatchList
            .Where (d => d is RedFoo);
}

//Horrifying duplicate code!:
public IEnumerable<AbstractFoo> GetMatchingFoos()
{
     return IEnumerable<AbstractFoo> exactMatchFoo = exactMatchList
            .Where (d => d is BlueFoo);
}

I'd like to be able to replace RedFoo / BlueFoo with something I can inject into a single method like this:

public IEnumerable<AbstractFoo> GetMatchingFoos(paramFoo)
{
    IEnumerable<AbstractFoo> exactMatchFoo = exactMatchList
    .Where (d => d is paramFoo.GetType()); //compile error
}

I tried using curly braces to access the local variable paramFoo, but that doesn't compile.

IEnumerable<AbstractFoo> exactMatchFoo = exactMatchList
.Where (d => is {paramFoo.GetType();}); //compile error

Also of note: AbstractFoo is an abstract class, that both RedFoo and BlueFoo inherit from. No interfaces in my code at this point.

How can the type of a local variable be captured inside a lambda expression in linq?

Community
  • 1
  • 1
David Vogel
  • 465
  • 8
  • 23

2 Answers2

3

Use the Enumerable.OfType to find all the elements of required type.

The OfType(IEnumerable) method returns only those elements in source that can be cast to type TResult. To instead receive an exception if an element cannot be cast to type TResult, use Cast(IEnumerable).

public IEnumerable<AbstractFoo> GetMatchingFoos<T>() where T : AbstractFoo
{
    return exactMatchList.OfType<T>();
}
Jaanus Varus
  • 3,508
  • 3
  • 31
  • 49
  • Of course there really isn't any purpose to having this method in the first place; the caller can just use `OfType` directly. – Servy Jun 05 '15 at 16:43
  • True that. But for the purposes of a public API, he might not want to reveal the non-generic collection or the collection with all the sub types of `AbstractFoo` at once. – Jaanus Varus Jun 05 '15 at 16:46
0

There's a LINQ extension method to find by type called OfType<T>.

See the following code snippet I made just now (also, you can run it here):

using System;
using System.Collections.Generic;
using System.Linq;

public class Program
{
    public class A {}

    public class B : A {}

    public class C {}

    public static void Main()
    {
        IEnumerable<A> result = new object [] { new A(), new B(), new C() }.OfType<A>();

            // Result: 2, because there're two instance of type A!
        Console.WriteLine(result.Count());
    }
}
Matías Fidemraizer
  • 63,804
  • 18
  • 124
  • 206