我希望能够动态构建表达式,这本质上是一个属性选择器。
我正在尝试使用此功能,因此我可以提供灵活的搜索UI,然后将选定的搜索参数转换为实体框架查询。
由于我正在使用的另一个库,我有大部分需要的东西,但我错过了最后一部分,它将我的查询字符串参数转换为另一个库所需的相应表达式选择器。
该库的参数为:
Expression<Func<TObject, TPropertyType>>
如果将其编入应用程序,将如何编码的示例如下:
Expression<Func<MyObject, int>> expression = x=> x.IntegerProperty;
但是,我需要能够动态生成这个表达式,因为重要的是我将知道的是对象的类型(MyObject)和属性名称作为字符串值(“IntegerProperty”)。属性值显然将映射到对象上的属性,该属性可以是任何非复杂类型。
基本上我认为我想找到一种动态构建表达式的方法,它指定要返回的正确对象属性以及返回值由该属性类型确定的位置。
psuedo代码:
string ObjectPropertyName
Type ObjectType
Type ObjectPropertyType = typeof(ObjectType).GetProperty(ObjectPropertyName).Property
Expression<Func<[ObjectType], [ObjectPropertyType]>> expression = x=> x.[ObjectPropertyName];
更新:
我已经达到了这个目标
ParameterExpression objectParameter = Expression.Parameter(type, "x");
MemberExpression objectProperty = Expression.Property(objectParameter, "PropertyNameString");
Expression<Func<ObjectType, int>> expression = Expression.Lambda<Func<ObjectType, int>>(objectProperty, objectParameter);
但我遇到的问题是返回类型并不总是int,但也可能是其他类型。
答案 0 :(得分:3)
做你所问的有点棘手,但并非不可能。由于属性类型在运行时才知道,因此您无法声明Expression<Func<,>>
,因此可以通过反射完成。
public static class QueryableExtension
{
public static object Build<Tobject>(this Tobject source, string propertyName)
{
var propInfo = typeof(Tobject).GetProperty(propertyName);
var parameter = Expression.Parameter(typeof(Tobject), "x");
var property = Expression.Property(parameter, propInfo);
var delegateType = typeof(Func<,>)
.MakeGenericType(typeof(Tobject), propInfo.PropertyType);
var lambda = GetExpressionLambdaMethod()
.MakeGenericMethod(delegateType)
.Invoke(null, new object[] { property, new[] { parameter } });
return lambda;
}
public static MethodInfo GetExpressionLambdaMethod()
{
return typeof(Expression)
.GetMethods()
.Where(m => m.Name == "Lambda")
.Select(m => new
{
Method = m,
Params = m.GetParameters(),
Args = m.GetGenericArguments()
})
.Where(x => x.Params.Length == 2
&& x.Args.Length == 1
)
.Select(x => x.Method)
.First();
}
}
用法 -
var expression = testObject.Build("YourPropertyName");
现在,这将使用返回类型的属性构建所需的表达式。但是因为我们不了解您的库,但我建议您通过反射调用您的库方法并传递包裹在对象下的表达式。
答案 1 :(得分:1)
正如我在评论中提到的,在不知道属性类型的情况下构建表达式很容易(即使使用嵌套属性支持):
static LambdaExpression MakeSelector(Type objectType, string path)
{
var item = Expression.Parameter(objectType, "item");
var body = path.Split('.').Aggregate((Expression)item, Expression.PropertyOrField);
return Expression.Lambda(body, item);
}
但是你需要找到一种方法来调用你的通用库方法 - 使用反射或动态调用。
答案 2 :(得分:0)
如果您同时将ObjectType
和ObjectPropertyType
作为通用类型参数,则可以使用Expression
类执行以下操作:
public static Expression<Func<TObject, TPropertyType>> Generate<TObject, TPropertyType>(
string property_name)
{
var parameter = Expression.Parameter(typeof (TObject));
return Expression.Lambda<Func<TObject, TPropertyType>>(
Expression.Property(parameter, property_name), parameter);
}
答案 3 :(得分:0)
有一个古老的有趣的图书馆DynamicLinq。可能对你有用。它扩展了System.Linq.Dynamic以支持在字符串中定义的Lambda表达式的执行。使用DynamicLinq你可以做一些事情,如:
abc.abstractproperty