views:

1495

answers:

4

I have LINQ statement that looks like this:

return ( from c in customers select new ClientEntity() { Name = c.Name, ... });

I'd like to be able to abstract out the select into its own method so that I can have different "mapping" option. What does my method need to return?

In essence, I'd like my LINQ query to look like this:

return ( from c in customers select new Mapper(c));

Edit:

This is for LINQ to SQL.

A: 

This is for linq to objects? Or for a linq to ?

Because ... select new Mapper(c), requires that 'c' is already materialized into an object, and then passed to the Mapper() CTor. (as 'c' is not known at the db level, only at the .NET level)

Frans Bouma
+1  A: 

You might have to use chained methods instead of using LINQ syntax, and then you'll be able to pass in any of a variety of Expression<Func<TSource, TResult>> values that you specify:

Expression<Func<CustomerTable, Customer>> someMappingExpression = c => new Customer { Name = c.Name };
return context.CustomerTable.Select(someMappingExpression);

UPDATE: Select takes a Func, not an Expression
UPDATE: The Select function that should be used does take an Expression<Func>, rather than just a Func.

bdukes
The code sample in this example is a syntax error, isn't it? Also the comment "Select takes a FUnc, not an Expression" is incorrect for Linq to SQL.
Daniel Earwicker
That's better! :)
Daniel Earwicker
+3  A: 

New answer now I've noticed that it's Linq to SQL... :)

If you look at the version of Select that works on IQueryable<T> it doesn't take a Func<In, Out>. Instead, it takes an Expression<Func<In, Out>>. The compiler knows how to generate such a thing from a lambda, which is why your normal code compiles.

So to have a variety of select mapping functions ready to use by passing them to Select, you could declared them like this:

private static readonly Expression<Func<CustomerInfo, string>> GetName = c => c.Name;

private static readonly Expression<Func<CustomerInfo, ClientEntity>> GetEntity = c => new ClientEntity { Name = c.Name, ... };

You would then use them like this:

var names = customers.Select(GetName);

var entities = customers.Select(GetEntity);
Daniel Earwicker
After tyring both your solution and bdukes, I must say your solution is better since it is able to parse the expression and actually build SQL out of it. bdukes' brought all of the results and then applied other clauses in memory.
Esteban Araya
A: 

BTW: The solutions described here will work only if you want to use the 'factored' part of the code in a separate query clause (e.g. Select). If you'd like to use it as part of a clause that also does some other thing (perhaps return anonymous type with some other information), you'll need to construct the whole expression tree dynamically using Expression.Xyz methods.

Alternatively you could use the trick for embedding lambda expressions that I described here:

Tomas Petricek