How to pass a C# Select () extension delegate or expression to a Repository?
Everyone projects once in a while:
var c = dc.Products.Select( p => new {p.id, p.name});
// results in c having properties of .id and .name
What if I want to refactor that in to a method. How would I pass the Select parameter?
var c = myFunction( p => new {p.id, p.name});
Product myFunction( ??? myLambda)
{
var c = dc.Products.Select( myLambda);
var result = new Product();
foreach( var myproperty in //property in myLambda)
{
result.XX // p开发者_JS百科roperty that matches, set it equal to myproperty
}
}
Obviously, I need to figure out reflection a lot more. :)
The type of the parameter should be something like Expression<Func<Product,object>>
. Also, I think you need your function to return an IEnumerable<Product>
with the properties set.
IEnumerable<Product> myFunction( Expression<Func<Product,object>> selector )
{
var products = new List<Product>();
foreach (var c in dc.Products.Select( selector ))
{
var product = new Product();
foreach (var property in c.GetType().GetProperties())
{
var productProperty = typeof(Product).GetProperty( property.Name );
productProperty.SetValue( product, property.GetValue( c, null ) );
}
products.Add( product );
}
return products;
}
Having said that I think I would probably have a separate model for each combination of properties being returned and use a generic method to return one of those.
IEnumerable<T> ProductPartial<T>( Func<Product,T> selector ) where T : new
{
return dc.Products.ToList().Select( selector );
}
used as
var pricing = repository.ProductPartial( p => new PricingModel( p ) );
Note: After thinking about it a little, if you are going to return a separate model, I think you may need to realize the query before you can do the conversion to the model anyway. In that case a Func<Product,T>
is probably most appropriate -- I've thrown an explicit ToList() in to make sure that the query is realized first so the select doesn't fail. If it were a Where
clause, that would be different. Even though this is slightly less efficient from a data transfer perspective (you're retrieving all the properties), I still prefer using using the specific model if you feel like you need to put the selection in the repository. Since you're only selecting part of the properties it feels wrong to pretend that you have an actual Product instance when you really don't.
You could at least look at any exists LINQ definitions, like http://msdn.microsoft.com/en-us/library/bb548891.aspx
So you need Func<TSource, TResult> myLambda
To be precise:
TResult myFunction<TResult>(Expression<Func<Product, TResult>> myLambda)
or
IEnumerable<TResult> myFunction<TResult>(Expression<Func<Product, TResult>> myLambda)
UPD: according to the @tvanfosson comment - the code has been changed a little.
精彩评论