Sto cercando di creare un'espressione che utilizzi FirstOrDefault con predicato su un'espressione di IEnumerable<TComparable>
ma mi sta dando questo errore: Il parametro 'o' non è stato associato nell'espressione di query LINQ to Entities specificata
Ho un'espressione linq come questa:
IEnumerable<string> names = new List<string>() { "abc", "def", "ghi" };
string name = names.FirstOrDefault(o => o.Contains("abc"));
public static Expression FirstOrDefault(this Expression expression, Type collectionValuesType, MethodInfo comparerMethod, string keyword)
{
MethodInfo firstOrDefaultMethod = typeof(Enumerable).GetMethods()
.FirstOrDefault(o => o.Name == "FirstOrDefault" && o.GetParameters().Length == 2)
.MakeGenericMethod(new Type[] { collectionValuesType });
Type firstOrDefaultDelegateType = typeof(Func<,>).MakeGenericType(collectionValuesType, typeof(bool));
ParameterExpression firstOrDefaultPredicateParameter = Expression.Parameter(collectionValuesType);
//THIS LINE binds the "o" in (o => o.Contains("abc")) , and it is where I'm stuck with since yesterday!
MemberExpression firstOrDefaultParameterO = Expression.Property(expression, typeof(string).GetProperty(???));
//o => o.ComparerMethod(keyword)
MethodCallExpression firstOrDefaultCompareExpression = Expression.Call(
firstOrDefaultParameterO,
comparerMethod,
Expression.Constant(keyword, typeof(string))
);
//expression.FirstOrDefault(firstOrDefaultCompareExpression);
return Expression.Call(
firstOrDefaultMethod,
expression,
Expression.Lambda(firstOrDefaultDelegateType, firstOrDefaultCompareExpression, Expression.Parameter(collectionValuesType))
);
}
Se avessi un tipo complesso, lo userei in questo modo:
public class Example { public string Name; }
//o => o.Name.Contains("abc"))
MemberExpression firstOrDefaultParameterO = Expression.Property(expression, typeof(Example).GetProperty("Name"));
Il problema è che non so come associare il tipo di stringa, poiché non ha una proprietà che darà il valore della proprietà.
BTW: collectionValuesType = typeof (stringa)
Ho modificato la domanda come suggerito per chiarire le cose.
Non è necessario costruire Expression.Property per tipi semplici come string.
Per esempio. Se devo costruire albero delle espressioni per il metodo OrderBy per il tipo Person
with Name
, costruirò l'albero delle espressioni in questo modo:
ParameterExpression pe = System.Linq.Expressions.Expression.Parameter(typeof(T), "p");
Expression<Func<T, TPropertyType>> expr = System.Linq.Expressions.Expression.Lambda<Func<T, TPropertyType>>(System.Linq.Expressions.Expression.Property(pe, propertyName), pe);
Ma per il tipo di stringa farò semplicemente: (Poiché la tua espressione sarà semplicemente x => x per i tipi di stringa)
If( typeof(T)==typeof(string))
{
ParameterExpression pe = System.Linq.Expressions.Expression.Parameter(typeof(T), "p");
Expression<Func<T, TPropertyType>> expr = System.Linq.Expressions.Expression.Lambda<Func<T, TPropertyType>>(pe,pe);
}
Probabilmente puoi usare lo stesso concetto per risolvere il tuo problema.
OMG, un giorno intero perso perché stavo passando il parametro sbagliato a Expression.Call alla fine.
return Expression.Call(
firstOrDefaultMethod,
expression,
Expression.Lambda(firstOrDefaultDelegateType, firstOrDefaultCompareExpression,
//THIS IS THE PROBLEM, it should be "firstOrDefaultPredicateParameter"
Expression.Parameter(collectionValuesType))
);
@ANewGuyInTown ringrazia per il tuo aiuto, dopo aver guardato la tua risposta ho fatto una "scansione completa" nel mio codice e ho trovato questo errore