純粋に.NETフレームワークを使用して、必要な述語式を動的に構築することで解決できます。
以下のコードサンプルを参照してください。基準に応じて、これは複数のプロパティでフィルタリングされます。IQuerable を使用したのは、これにより、Entity Framework などのリモート シナリオとしての両方のインメモリが有効になるためです。Entity Framework を使用する場合は、EntitySQL 文字列を動的に構築することもできます。私はそれがより良いパフォーマンスになることを期待しています。
関連するリフレクションのごく一部があります (GetProperty)。ただし、これは BuildPredicate メソッド内でキャッシュを実行することで改善できます。
public class Item
{
public string Color { get; set; }
public int Value { get; set; }
public string Category { get; set; }
}
class Program
{
static void Main(string[] args)
{
var list = new List<Item>()
{
new Item (){ Category = "Big", Color = "Blue", Value = 5 },
new Item (){ Category = "Small", Color = "Red", Value = 5 },
new Item (){ Category = "Big", Color = "Green", Value = 6 },
};
var criteria = new Dictionary<string, object>();
criteria["Category"] = "Big";
criteria["Value"] = 5;
var query = DoDynamicWhere(list.AsQueryable(), criteria);
var result = query.ToList();
}
static IQueryable<T> DoDynamicWhere<T>(IQueryable<T> list, Dictionary<string, object> criteria)
{
var temp = list;
//create a predicate for each supplied criterium and filter on it.
foreach (var key in criteria.Keys)
{
temp = temp.Where(BuildPredicate<T>(key, criteria[key]));
}
return temp;
}
//Create i.<prop> == <value> dynamically
static Expression<Func<TType, bool>> BuildPredicate<TType>(string property, object value)
{
var itemParameter = Expression.Parameter(typeof(TType), "i");
var expression = Expression.Lambda<Func<TType, bool>>(
Expression.Equal(
Expression.MakeMemberAccess(
itemParameter,
typeof(TType).GetProperty(property)),
Expression.Constant(value)
),
itemParameter);
return expression;
}
}