C# 表达式树:获取动态对象的属性值

C# 表达式树:获取动态对象的属性值,c#,reflection,C#,Reflection,我有一个要按自定义属性查询的动态对象列表。换句话说,如果我不去思考的话,它会是这样的: IEnumerable FilterUsers(IEnumerable用户,字符串selectedValue) { users.Where(user=>user.Name==selectedValue); } 到目前为止,我已经提出了以下实现,如果键入了用户,它就可以工作: IEnumerable FilterUsers(IEnumerable用户、string selectedField、string s

我有一个要按自定义属性查询的动态对象列表。换句话说,如果我不去思考的话,它会是这样的:

IEnumerable FilterUsers(IEnumerable用户,字符串selectedValue)
{
users.Where(user=>user.Name==selectedValue);
}
到目前为止,我已经提出了以下实现,如果键入了
用户
,它就可以工作:

IEnumerable FilterUsers(IEnumerable用户、string selectedField、string selectedValue)
{
labelTargetReturnTarget=Expression.Label(typeof(bool));
ParameterExpression userParameter=Expression.Parameter(typeof(User));
MemberExpression userSelectedField=Expression.Property(userParameter,selectedField);
表达式测试=Expression.Equal(userSelectedField,Expression.Constant(selectedValue));
表达式iftrue=Expression.Return(returnTarget,Expression.Constant(true));
表达式iffalse=Expression.Return(returnTarget,Expression.Constant(false));
var ex=Expression.Block(
表达式IfThenElse(测试、iftrue、iffalse),
Expression.Label(returnTarget,Expression.Constant(false));
var where子句=表达式.Lambda(
前任,
新参数表达式[]{userParameter}
).Compile();
返回users.Where(user=>whereClause(user));
}
我真正想做的是让用户成为动态对象:

IEnumerable FilterUsers(IEnumerable用户、string selectedField、string selectedValue){
// ...
ParameterExpression userParameter=表达式。参数(类型(对象));/???
MemberExpression userSelectedField=Expression.Property(userParameter,selectedField);//抛出
// ...
}
这引发以下异常:
未为类型“System.Object”(参数“propertyName”)定义实例属性“Name”
。我错过了什么


或者,我如何使用
字典

使用
动态
这里没有什么帮助:如果可以,最好使用泛型:

IEnumerable<T> FilterUsers<T>(IEnumerable<T> users, string selectedField, string selectedValue)
{
    var userParameter = Expression.Parameter(typeof(T));
    var userSelectedField = Expression.Property(userParameter, selectedField);
    // etc...
}

但是,要注意,您要枚举
用户两次,这可能是一件坏事。您最好自己获取
IEnumerator
并显式使用它。

使用
动态
这里对您没有多大帮助:如果可以,您最好使用泛型:

IEnumerable<T> FilterUsers<T>(IEnumerable<T> users, string selectedField, string selectedValue)
{
    var userParameter = Expression.Parameter(typeof(T));
    var userSelectedField = Expression.Property(userParameter, selectedField);
    // etc...
}

但是,要注意,您要枚举
用户两次,这可能是一件坏事。您最好自己获取
IEnumerator
并明确使用它。

正如@canton7所说,您应该使用通用方法。我还看到在你的问题中你指定了你要寻找的属性,为什么不使用常规的旧反射呢

public static IEnumerable<T> FilterItems<T>(IEnumerable<T> items, string property, string value)
{
  var prop = typeof(T).GetProperties().First(p => p.Name == property);      
  return items.Where(i => prop.GetValue(i).ToString().Contains(value));
}
公共静态IEnumerable筛选器项(IEnumerable项、字符串属性、字符串值)
{
var prop=typeof(T).GetProperties().First(p=>p.Name==property);
returnitems.Where(i=>prop.GetValue(i).ToString()包含(value));
}

当然,应该增强代码以处理不同的错误。…

正如@canton7所说,您应该使用通用方法。我还看到在你的问题中你指定了你要寻找的属性,为什么不使用常规的旧反射呢

public static IEnumerable<T> FilterItems<T>(IEnumerable<T> items, string property, string value)
{
  var prop = typeof(T).GetProperties().First(p => p.Name == property);      
  return items.Where(i => prop.GetValue(i).ToString().Contains(value));
}
公共静态IEnumerable筛选器项(IEnumerable项、字符串属性、字符串值)
{
var prop=typeof(T).GetProperties().First(p=>p.Name==property);
returnitems.Where(i=>prop.GetValue(i).ToString()包含(value));
}

当然,应该增强代码以处理不同的错误……

最有可能的是速度。在您的情况下,最好使用
typeof(T)
而不是
items.First().GetType()
,以防这些项具有不同的属性types@canton7我以前没有真正使用过
表达式
名称空间,所以我可能做错了什么,但是,在我的方法和他的方法上迭代1000次,平均需要6毫秒和180毫秒,共运行3次。看起来表情并不是更快。谢谢你指出打字错误(T)也。。。更新答案。速度,最有可能。在您的情况下,最好使用
typeof(T)
而不是
items.First().GetType()
,以防这些项具有不同的属性types@canton7我以前没有真正使用过
表达式
名称空间,所以我可能做错了什么,但是,在我的方法和他的方法上迭代1000次,平均需要6毫秒和180毫秒,共运行3次。看起来表情并不是更快。谢谢你指出打字错误(T)也。。。更新答案。
用户
由生成器生成为
新{…}
-无需担心时髦的数据,但不可能为所有可能的变体创建特定类型。我可以这样做:
cs IEnumerable FilterUsers(IEnumerable users,string selectedField,string selectedValue){var firstUser=users.FirstOrDefault();if(firstUser==null)返回Enumerable.Empty();//所有这些都应该具有相同的结构var userParameter=Expression.Parameter(firstUser.GetType());var userSelectedField=Expression.Property(userParameter,selectedField);}
Yep如果它们都是同一类型,则应该可以使用。您可能需要声明object类型的参数并添加表达式。转换为该类型有一个改进,但它仍然会在不同的位置引发异常。更多详情:@Arvigeus请参阅我之前评论的第二部分:“您可能需要声明object类型的参数并添加一个表达式。转换为该类型”您能否将此作为答案发布,以便我将其标记为已接受<代码>用户
是由构建器以
新{…}
的形式生成的-无需担心时髦的数据,但不可能为所有可能的变体创建特定类型。我可以这样做:
cs IEnumerable FilterUsers(IEnumerable用户,string selectedField,string selectedValue){var firstUser=users.FirstOrDefault();if(firstUser==null)返回