我有一个WCF服务,它公开了一堆返回业务对象的方法.它的内部有一个漂亮的存储库层,它使用如下接口方法:
IEnumerable<User> GetUsers(Func<User, bool> predicate);
因此,如果我希望所有用户都属于给定角色,则可以这样做:
var plebs = GetUsers(u => u.Roles.Contains(plebRole));
现在,我想对WCF界面公开任何可以满足的过滤器思想. WCF api必须可供非.Net客户端访问,因此我想使用(相对)简单类型.
我有一个包含属性名称和值的Filter对象:
[DataContract] public class Filter {
[DataMember] public string Property { get; set; }
[DataMember] public string Value { get; set; }
}
所以现在我可以公开这样的WCF方法:
IEnumerable<User> GetUsers(IEnumerable<Filter> filters);
然后,我可以根据客户端过滤器中传入的内容构建谓词.现在变得凌乱:
private static Expression<Func<T, bool>> GetPredicate<T>(Filter filter)
{
var knownPredicates = GetKnownPredicates<T>(filter.Value);
var t = typeof(T);
return knownPredicates.ContainsKey(t) && knownPredicates[t].ContainsKey(filter.Property)
? knownPredicates[t][filter.Property]
: True<T>();
}
private static Dictionary<Type, Dictionary<string, Expression<Func<T, bool>>>> GetKnownPredicates<T>(string value)
{
// ReSharper disable PossibleNullReferenceException
return new Dictionary<Type, Dictionary<string, Expression<Func<T, bool>>>>
{
{
typeof (User), new Dictionary<string, Expression<Func<T, bool>>>
{
{ "Forename", x => (x as User).Forename == value },
{ "IsAdult", x => (x as User).IsAdult.ToString() == value },
...
}
},
{
typeof (Group), new Dictionary<string, Expression<Func<T, bool>>>
{
{ "Name", x => (x as Group).Name == value },
...
}
},
...
};
// ReSharper restore PossibleNullReferenceException
}
在我开始编写GetKnownPredicates方法之前,代码并没有真正发臭.现在可以了.我如何解决它?
解决方法:
如果您想成为超级幻想者,可以使用System.Linq.Expressions.Expression类根据传入的过滤器动态构建谓词.您知道要搜索的类型,因此您所要做的就是使用Filter.Property和带有Filter.Value的常量表达式进行create a property expression的操作.使用它们来构成一个相等的表达式,您已经接近终点线.
习惯于编写表达式可能会很痛苦,但是调试器确实很有用,并且在编写表达式时会为您显示表达式的代码,因此请尝试一下!