我想知道是否可以在过滤器表达式
中使“属性名称”动态化考虑场景
List<Person> GetPerson(int countryID, int stateID, int cityID, int zip)
{
//List of person can be filtered based on below line of code
List<Person> filteredPersons= persons.FindAll(rule => rule.CountryID == countryID).ToList();
//is it possible to specify ".Country" dynamically. something like
List<Person> filteredPersons= persons.FindAll(rule => rule."propertyName"== countryID).ToList();
}
答案 0 :(得分:2)
考虑到您的示例,您可以使用的一种方法是使用.Where()
扩展名而不是FindAll()
这可以允许您手动构建表达式。一个简单的例子如下。
static List<Person> GetPerson(int countryID, int stateID, int cityID, int zip)
{
//create a new expression for the type of person this.
var paramExpr = Expression.Parameter(typeof(Person));
//next we create a property expression based on the property named "CountryID" (this is case sensitive)
var property = Expression.Property(paramExpr, "CountryID");
//next we create a constant express based on the country id passed in.
var constant = Expression.Constant(countryID);
//next we create an "Equals" express where property equals containt. ie. ".CountryId" = 1
var idEqualsExpr = Expression.Equal(property, constant);
//next we convert the expression into a lamba expression
var lExpr = Expression.Lambda<Func<Person, bool>>(idEqualsExpr, paramExpr);
//finally we query our dataset
return persons.AsQueryable().Where(lExpr).ToList();
}
所以这看起来很多代码,但我们基本上已经完成的是手动构造表达式树,其最终结果看起来类似于(并且起作用)
return persons.AsQueryable().Where(p => p.CountryId = countryId);
现在我们可以采用这个方法,假设你想使用和/或基于方法调用来查询多个属性。也就是说,您可以将所有“过滤器”参数更改为Nullable,并检查是否传递了值,我们会对其进行过滤,例如。
static List<Person> GetPerson(int? countryID = null, int? stateID = null, int? cityID = null, int? zip = null)
{
//create a new expression for the type of person this.
var paramExpr = Expression.Parameter(typeof(Person));
//var equalExpression = Expression.Empty();
BinaryExpression equalExpression = null;
if (countryID.HasValue)
{
var e = BuildExpression(paramExpr, "CountryId", countryID.Value);
if (equalExpression == null)
equalExpression = e;
else
equalExpression = Expression.And(equalExpression, e);
}
if (stateID.HasValue)
{
var e = BuildExpression(paramExpr, "StateID", stateID.Value);
if (equalExpression == null)
equalExpression = e;
else
equalExpression = Expression.And(equalExpression, e);
}
if (equalExpression == null)
{
return new List<Person>();
}
//next we convert the expression into a lamba expression
var lExpr = Expression.Lambda<Func<Person, bool>>(equalExpression, paramExpr);
//finally we query our dataset
return persons.AsQueryable().Where(lExpr).ToList();
}
static BinaryExpression BuildExpression(Expression expression, string propertyName, object value)
{
//next we create a property expression based on the property named "CountryID" (this is case sensitive)
var property = Expression.Property(expression, propertyName);
//next we create a constant express based on the country id passed in.
var constant = Expression.Constant(value);
//next we create an "Equals" express where property equals containt. ie. ".CountryId" = 1
return Expression.Equal(property, constant);
}
现在这是更多的代码,但正如您所看到的,我们现在接受所有参数的null
值并构建我们对其他属性的查询。
现在你可以进一步(假设需要更通用的方法)传递Dictionary<string, object>
属性\值来进行查询。这可以作为下面列出的IEnumerable<T>
的扩展方法来完成。
public static class LinqExtensions
{
public static IEnumerable<T> CustomParameterQuery<T>(this IEnumerable<T> entities, Dictionary<string, object> queryVars)
{
if (entities.Count() == 0 || queryVars.Count == 0)
{
return entities;
}
//create a new expression for the type of person this.
var paramExpr = Expression.Parameter(typeof(T));
BinaryExpression equalExpression = null;
foreach (var kvp in queryVars)
{
var e = BuildExpression(paramExpr, kvp.Key, kvp.Value);
if (equalExpression == null)
equalExpression = e;
else
equalExpression = Expression.And(equalExpression, e);
}
if (equalExpression == null)
{
return new T[0];
}
//next we convert the expression into a lamba expression
var lExpr = Expression.Lambda<Func<T, bool>>(equalExpression, paramExpr);
//finally we query our dataset
return entities.AsQueryable().Where(lExpr);
}
static BinaryExpression BuildExpression(Expression expression, string propertyName, object value)
{
//next we create a property expression based on the property name
var property = Expression.Property(expression, propertyName);
//next we create a constant express based on the country id passed in.
var constant = Expression.Constant(value);
//next we create an "Equals" express where property equals containt. ie. ".CountryId" = 1
return Expression.Equal(property, constant);
}
}
现在可以轻松地将其称为:
var dict = new Dictionary<string, object>
{
{ "CountryID", 1 },
{ "StateID", 2 }
};
var e = persons.CustomParameterQuery(dict);
现在很明显这不是一个完美的例子,但应该让你朝着正确的方向前进。现在,您可以在组合表达式时使用Expression.Or
而不是Expression.And
来支持“OR”语句等。
我必须添加这是非常容易出错的,因为它要求属性名称与实体完全相同,您可以使用T
上的反射并确定PropertyName是否存在以及它是否正确套管。强>
答案 1 :(得分:0)
在NuGet中搜索 System.Linq.Dynamic 。这是开始使用Dynamic Linq的最简单方法。