tags:

views:

559

answers:

3

I'd like to pass a Linq query to a method, how do I specify the argument type?

My link query look something like:

var query =
    from p in pointList
    where p.X < 100
    select new {X = p.X, Y = p.Y}

clearly I'm new to Linq, and will probably get rid of the receiving method eventually when I convert the rest of my code, but it seems like something I should know...

thanks

+8  A: 

You'll need to either use a normal type for the projection, or make the method you're passing it to generic as well (which will mean you can't do as much with it). What exactly are you trying to do? If you need to use the X and Y values from the method, you'll definitely need to create a normal type. (There are horribly hacky ways of avoiding it, but they're not a good idea.)

Note: some other answers are currently talking about IQueryable<T>, but there's no indication that you're using anything more than LINQ to Objects, in which case it'll be an IEnumerable<T> instead - but the T is currently an anonymous type. That's the bit you'll need to work on if you want to use the individual values within each item. If you're not using LINQ to Objects, please clarify the question and I'll edit this answer.

For example, taking your current query (which is slightly broken, as you can't use two projection initializers twice with the same name X). You'd create a new type, e.g. MyPoint

public sealed class MyPoint
{
    private readonly int x;
    private readonly int y;
    public int X { get { return x; } }
    public int Y { get { return y; } }

    public MyPoint(int x, int y)
    {
        this.x = x;
        this.y = y;
    }
}

Your query would then be:

var query =
    from p in pointList
    where p.X < 100
    select new MyPoint(p.X, p.Y);

You'd then write your method as:

public void SomeMethod(IEnumerable<MyPoint> points)
{
    ...
}

And call it as SomeMethod(query);

Jon Skeet
So many people disagreeing with Jon, is that even possible? I mean you almost wrote *the* book on C#.
Samuel
I'm trying to step by step convert code to use linq while testing it out as I go. I now have the data set as linq in the beginning of the call sequence so end up with the mess of converting it to the old code halfway down. Seems like I'll be better off converting it all and then testing
Oskar
@Samuel: A lot of people see "LINQ" and immediately think "LINQ to SQL" (or entity framework etc). Personally I find LINQ to Objects much more useful for day-to-day work :)
Jon Skeet
Disagreeing with Jon? BLASPHEMERS!!!! Stone the heretics!
SirDemon
I agree with Jon, I just got my answer in before he did... and I had to correct my answer.
irperez
fixed the questionGreat answer, the trick you show is to select out a non-generic type and then I'm back into old C#. Now that my code works I'll continue converting the rest of the code, but will probably be back soon with questions on dynamically creating queries (matching the same result type)
Oskar
A: 
public void DoSomething(IQueryable query) { ... }

public void DoSomething<T>(IQueryable<T> query) { ... }

And just in case (if you will need passing expressions):

public void DoSomething(Expression exp) { ... }
Koistya Navin
The type of "query" is certainly not an Expression. It's likely to be an IEnumerable<T> or IQueryable<T>.
Jon Skeet
Yeah, I just thought he might be insteresting in passing expressions as well and this gonna be his next question :)
Koistya Navin
+1  A: 

While both tvanfosson and Jon are correct, you can just write your function to accept an IEnumerable<T> (you can either make your function generic or you can specify the specific concrete generic version you want, which is more likely the correct option) as LINQ to Objects produces an IEnumerable<T> and LINQ to SQL produces an IQueryable<T>, which implements IEnumerable<T>. This option should allow you to be source-agnostic.

Adam Robinson