我试图在调用contains之前将DateTime转换为String。尽管我努力将一个表达式的结果放到另一个表达式中,但我却悲惨地失败了。
代码源自此question jqgrid的最高答案,其中asp.net webmethod和json使用排序,分页,搜索和LINQ - 但需要动态运算符。
假设我有以下方法作为question中的StringExtension:
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;
}
}
因此我也从question获得了以下方法,然后我将其改编为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);
}
我收到以下异常。
LINQ to Entities无法识别方法'System.String ToString(System.String)'方法,并且此方法无法转换为商店表达式。
答案 0 :(得分:2)
我怀疑你想要这样的东西(从以前的版本修复):
using System;
using System.Linq.Expressions;
public class Person
{
public DateTime DateOfBirth { get; set; }
}
public class Test
{
static void Main()
{
var expr = Foo<Person>("DateOfBirth", "1976");
Person p = new Person
{
DateOfBirth = new DateTime(1976, 6, 19)
};
Console.WriteLine(expr.Compile()(p));
}
static Expression<Func<T, bool>> Foo<T>(string propertyName,
string searchValue)
{
ParameterExpression parameter = Expression.Parameter(typeof(T), "x");
Expression property = Expression.Property(parameter, propertyName);
Expression toStringCall = Expression.Call(
property, "ToString",
null,
new[] { Expression.Constant("D") });
Expression containsCall = Expression.Call(
toStringCall, "Contains",
null,
new[] { Expression.Constant(searchValue) });
return Expression.Lambda<Func<T, bool>>(containsCall, parameter);
}
}
请注意,“null”值表示它是非泛型方法调用。
答案 1 :(得分:0)
试试这段代码......
致电ToExpression(...)...... 防爆。 ToExpression(NULL,Product.Name, “==”, “测试”); 这里。 Product.Name是嵌套属性..
public static Expression<Func<T, bool>> ToExpression<T>(string andOrOperator, string propName, string opr, string value, Expression<Func<T, bool>> expr = null)
{
Expression<Func<T, bool>> func = null;
try
{
ParameterExpression paramExpr = Expression.Parameter(typeof(T));
var arrProp = propName.Split('.').ToList();
Expression binExpr = null;
string partName = string.Empty;
arrProp.ForEach(x =>
{
Expression tempExpr = null;
partName = partName.IsNull() ? x : partName + "." + x;
if (partName == propName)
{
var member = NestedExprProp(paramExpr, partName);
var type = member.Type.Name == "Nullable`1" ? Nullable.GetUnderlyingType(member.Type) : member.Type;
tempExpr = ApplyFilter(opr, member, Expression.Convert(ToExprConstant(type, value), member.Type));
}
else
tempExpr = ApplyFilter("!=", NestedExprProp(paramExpr, partName), Expression.Constant(null));
if (binExpr != null)
binExpr = Expression.AndAlso(binExpr, tempExpr);
else
binExpr = tempExpr;
});
Expression<Func<T, bool>> innerExpr = Expression.Lambda<Func<T, bool>>(binExpr, paramExpr);
if (expr != null)
innerExpr = (andOrOperator.IsNull() || andOrOperator == "And" || andOrOperator == "AND" || andOrOperator == "&&") ? innerExpr.And(expr) : innerExpr.Or(expr);
func = innerExpr;
}
catch { }
return func;
}
private static MemberExpression NestedExprProp(Expression expr, string propName)
{
string[] arrProp = propName.Split('.');
int arrPropCount = arrProp.Length;
return (arrPropCount > 1) ? Expression.Property(NestedExprProp(expr, arrProp.Take(arrPropCount - 1).Aggregate((a, i) => a + "." + i)), arrProp[arrPropCount - 1]) : Expression.Property(expr, propName);
}
private static Expression ToExprConstant(Type prop, string value)
{
if (value.IsNull())
return Expression.Constant(value);
object val = null;
switch (prop.FullName)
{
case "System.Guid":
val = value.ToGuid();
break;
default:
val = Convert.ChangeType(value, Type.GetType(prop.FullName));
break;
}
return Expression.Constant(val);
}
private static Expression ApplyFilter(string opr, Expression left, Expression right)
{
Expression InnerLambda = null;
switch (opr)
{
case "==":
case "=":
InnerLambda = Expression.Equal(left, right);
break;
case "<":
InnerLambda = Expression.LessThan(left, right);
break;
case ">":
InnerLambda = Expression.GreaterThan(left, right);
break;
case ">=":
InnerLambda = Expression.GreaterThanOrEqual(left, right);
break;
case "<=":
InnerLambda = Expression.LessThanOrEqual(left, right);
break;
case "!=":
InnerLambda = Expression.NotEqual(left, right);
break;
case "&&":
InnerLambda = Expression.And(left, right);
break;
case "||":
InnerLambda = Expression.Or(left, right);
break;
case "LIKE":
InnerLambda = Expression.Call(left, typeof(string).GetMethod("Contains", new Type[] { typeof(string) }), right);
break;
case "NOTLIKE":
InnerLambda = Expression.Not(Expression.Call(left, typeof(string).GetMethod("Contains", new Type[] { typeof(string) }), right));
break;
}
return InnerLambda;
}
public static Expression<Func<T, object>> PropExpr<T>(string PropName)
{
ParameterExpression paramExpr = Expression.Parameter(typeof(T));
var tempExpr = Extentions.NestedExprProp(paramExpr, PropName);
return Expression.Lambda<Func<T, object>>(Expression.Convert(Expression.Lambda(tempExpr, paramExpr).Body, typeof(object)), paramExpr);
}
public static IQueryOver<T, T> OrderBy<T>(this IQueryOver<T, T> Collection, string sidx, string sord)
{
return sord == "asc" ? Collection.OrderBy(NHibernate.Criterion.Projections.Property(sidx)).Asc : Collection.OrderBy(NHibernate.Criterion.Projections.Property(sidx)).Desc;
}
public static Expression<Func<T, TResult>> And<T, TResult>(this Expression<Func<T, TResult>> expr1, Expression<Func<T, TResult>> expr2)
{
var invokedExpr = Expression.Invoke(expr2, expr1.Parameters.Cast<Expression>());
return Expression.Lambda<Func<T, TResult>>(Expression.AndAlso(expr1.Body, invokedExpr), expr1.Parameters);
}
public static Expression<Func<T, bool>> Or<T>(this Expression<Func<T, bool>> expr1, Expression<Func<T, bool>> expr2)
{
var invokedExpr = Expression.Invoke(expr2, expr1.Parameters.Cast<Expression>());
return Expression.Lambda<Func<T, bool>>(Expression.OrElse(expr1.Body, invokedExpr), expr1.Parameters);
}