我是C#/ Unity的新手,请原谅我。
我正在编写一个过滤系统,它将在运行时通过类的任何属性过滤列表。 我正在计划建立一些过滤列表的地方(我知道我可以点击服务器获取我需要的列表,但目前只想过滤我已经拥有的数据)
假设我有一个包含4个属性的“MyClass”类列表:“param1”..“param4”
如果我想通过param1和param2正常过滤它,我可以这样做:
List<MyClass> myList = new List<MyClass>(existinglist);
myList = myList.Where(g => g.param1 == somevalue && g.param2 == someothervalue).ToList();
我怎么能在运行时生成相同的where子句?
谢谢!
答案 0 :(得分:1)
您可以编写如下的扩展方法:
public static IEnumerable<T> Where<T>(this IEnumerable<T> source, string propName, object value)
{
var type = typeof(T);
var propInfo = type.GetProperty(propName,BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance);
var parameterExpr = Expression.Parameter( type, "x" ); //x
var memberAccessExpr = Expression.MakeMemberAccess( parameterExpr, propInfo ); //x.Prop
var lambda = Expression.Lambda( Expression.Equal(memberAccessExpr, Expression.Constant(value)),
parameterExpr ); //x=>x.Prop==value
var mi = typeof(Enumerable)
.GetMethods()
.Where(m => m.Name == "Where")
.First(m => m.GetParameters().Count() == 2)
.MakeGenericMethod(type);
return (IEnumerable<T>)mi.Invoke(null, new object[] { source, lambda.Compile() });
}
您现在可以将其用作
var test = new[] { new { a = 1 }, new { a = 2 } }.Where("a", 1).ToList();
答案 1 :(得分:0)
您可以使用辅助方法,该方法根据传递的过滤器列表动态构建和编译lambda。我使用KeyValuePair<string, object>
来表示过滤器信息(属性名称为Key
,Value
- 以及属性值),但当然可以针对其他数据结构进行调整(如自定义类等)
public static class EnumerableExtensions
{
public static IEnumerable<T> Where<T>(this IEnumerable<T> source, IEnumerable<KeyValuePair<string, object>> filters)
{
if (filters == null || !filters.Any()) return source;
var parameter = Expression.Parameter(typeof(T), "x");
var body = filters
.Select(filter => Expression.Equal(
Expression.PropertyOrField(parameter, filter.Key),
Expression.Constant(filter.Value)))
.Aggregate(Expression.AndAlso);
var predicate = Expression.Lambda<Func<T, bool>>(body, parameter);
return source.Where(predicate.Compile());
}
}
样本用法:
var filters = new List<KeyValuePair<string, object>>
{
new KeyValuePair<string, object>("param1", somevalue),
new KeyValuePair<string, object>("param2", someothervalue),
};
var myList = existinglist.Where(filters).ToList();
答案 2 :(得分:-1)
lambda表达式只是函数的简写。所以你可以用任何带有Myclass并返回bool的函数替换lambda。然后在该方法中编写代码来动态评估您需要的内容 - 如果需要,可以使用反射。
myList = myList.Where(myFunction).ToList();