I have a lambda expression as follows:
var source = new List<Entidade>();
var z = source.Select<Entidade, Resultado>(
s =>
new Resultado
{
Detalhes =
new List<DetalheResultado>(
s.Detalhes.Select<Detalhe, DetalheResultado>(
t => new DetalheResultado { Id = t.Id, Valor = t.Valor }))
});
I am trying to execute the same query with Expressions with the following code:
ParameterExpression sourceItem = Expression.Parameter(typeof(Entidade), "s");
var source3 = Expression.Parameter(typeof(Detalhe), "t");
var property3 = typeof(DetalheResultado).GetProperty("Id");
var member3 = Expression.Property(source3, "Id");
var itemResult3 = Expression.New(typeof(DetalheResultado).GetConstructor(Type.EmptyTypes));
var memberBinding3 = Expression.Bind(property3, member3);
var memberInit3 = Expression.MemberInit(itemResult3, memberBinding3);
var selector3 = Expression.Lambda(memberInit3, source3);
var detalhes = Expression.Property(sourceItem, "Detalhes");
// here you get an error
var lista3 = Expression.Call(
typeof(Queryable),
"Select",
new Type[] { typeof(Detalhe), typeof(DetalheResultado) },
detalhes,
selector3);
var listaResultado = typeof(DetalheResultado).GetProperty("Detalhes");
var memberBindigs4 = Expression.Bind(listaResultado, lista3);
...
but running this code I got the error:
No generic method 'Select ' on ' System.Linq.Queryable ' type is compatible with the arguments and the supplied type arguments. Any argument must be provided if the method is not generic.
I consulted the DebugView expression and implemented expressions as its return, but get the aforementioned error.
Any suggestions?
I have never had luck with using that Expression.Call
method on the LINQ generic methods. I always fetch it separately (see variables firstSelectMethod
and secondSelectMethod
). I don't know why, and if someone else knows why that won't work, I would be much obliged. The below code works, though I made some assumptions about what your classes look like.
Please note that I substituted Queryable
for Enumerable
.
var paramS = Expression.Parameter(typeof(Entidade), "s");
var paramT = Expression.Parameter(typeof(Detalhe), "t");
var firstSelectMethod = typeof(Enumerable).GetMethods().First(m => m.Name == "Select").MakeGenericMethod(typeof(Entidade), typeof(Resultado));
var secondSelectMethod = typeof(Enumerable).GetMethods().First(m => m.Name == "Select").MakeGenericMethod(typeof(Detalhe), typeof(DetalheResultado));
var lista4 = Expression.Call(
firstSelectMethod,
Expression.Constant(source),
Expression.Lambda(
Expression.MemberInit(
Expression.New(typeof(Resultado).GetConstructor(Type.EmptyTypes)),
Expression.Bind(
typeof(Resultado).GetProperty("Detalhes"),
Expression.New(
typeof(List<DetalheResultado>).GetConstructor(new Type[] {typeof(IEnumerable<DetalheResultado>)}),
Expression.Call(
secondSelectMethod,
Expression.Property(
paramS,
"Detalhes"
),
Expression.Lambda(
Expression.MemberInit(
Expression.New(typeof(DetalheResultado).GetConstructor(Type.EmptyTypes)),
Expression.Bind(
typeof(DetalheResultado).GetProperty("Id"),
Expression.Property(paramT, "Id")
),
Expression.Bind(
typeof(DetalheResultado).GetProperty("Valor"),
Expression.Property(paramT, "Valor")
)
),
paramT
)
)
)
)
),
paramS
)
);