J'essaie de convertir un DateTime en une chaîne avant de l'appeler contient. Cependant, malgré mes efforts pour mettre le résultat d'une expression dans une autre, j'échoue misérablement.Comment imbriquer un appel à une méthode dans un appel à une méthode à l'aide Expression.Call
Le code est dérivé de la réponse la plus élevée à ce question jqgrid avec asp.net webmethod et json travaillant avec le tri, la pagination, la recherche et LINQ - mais nécessite des opérateurs dynamiques.
Supposons que je le procédé suivant comme StringExtension du question:
public static class StringExtensions
{
public static MemberExpression ToMemberExpression(this string source, ParameterExpression p)
{
if (p == null)
throw new ArgumentNullException("p");
string[] properties = source.Split('.');
Expression expression = p;
Type type = p.Type;
foreach (var prop in properties)
{
var property = type.GetProperty(prop);
if (property == null)
throw new ArgumentException("Invalid expression", "source");
expression = Expression.MakeMemberAccess(expression, property);
type = property.PropertyType;
}
return (MemberExpression)expression;
}
}
J'ai donc la méthode suivante aussi de la question que je puis adapté pour DateTime.
public virtual Expression<Func<T, bool>> CreateExpression<T>(string searchField, string searchString, string searchOper)
{
Expression exp = null;
var p = Expression.Parameter(typeof(T), "p");
Expression propertyAccess = searchField.ToMemberExpression(p);
switch (searchOper)
{
case "bw":
exp = Expression.Call(propertyAccess, typeof(string).GetMethod("StartsWith", new Type[] { typeof(string) }), Expression.Constant(searchString));
break;
// New code by me
case "cn":
if (propertyAccess.Type == typeof(DateTime))
{
// My faulty logic - from Jon Skeet answer below
Expression toStringCall = Expression.Call(
propertyAccess, "ToString",
null,
new[] { Expression.Constant("D") });
Expression containsCall = Expression.Call(
toStringCall, "Contains",
null,
new[] { Expression.Constant(searchString) });
exp = containsCall;
}
else
{
// Unchanged
exp = Expression.Call(propertyAccess, typeof(string).GetMethod("Contains", new Type[] { typeof(string) }), Expression.Constant(searchString));
}
break;
case "ew":
exp = Expression.Call(propertyAccess, typeof(string).GetMethod("EndsWith", new Type[] { typeof(string) }), Expression.Constant(searchString));
break;
case "gt":
exp = Expression.GreaterThan(propertyAccess, Expression.Constant(searchString, propertyAccess.Type));
break;
case "ge":
exp = Expression.GreaterThanOrEqual(propertyAccess, Expression.Constant(searchString, propertyAccess.Type));
break;
case "lt":
exp = Expression.LessThan(propertyAccess, Expression.Constant(searchString, propertyAccess.Type));
break;
case "le":
exp = Expression.LessThanOrEqual(propertyAccess, Expression.Constant(searchString, propertyAccess.Type));
break;
case "eq":
exp = Expression.Equal(propertyAccess, Expression.Constant(searchString.ToType(propertyAccess.Type), propertyAccess.Type));
break;
case "ne":
exp = Expression.NotEqual(propertyAccess, Expression.Constant(searchString, propertyAccess.Type));
break;
default:
return null;
}
return (Expression<Func<T, bool>>)Expression.Lambda(exp, p);
}
Je reçois l'exception suivante.
LINQ to Entities ne reconnaît pas la méthode System.String ToString (System.String) de méthode, et cette méthode ne peut pas être traduite dans une expression de magasin.
Pourquoi pas? Ce qui se produit? – SLaks
Qu'est-ce que 'propertyAccess'? –