我有一个WCF服务,它公开了一堆返回业务对象的方法。在它的引擎盖下,它有一个很好的存储库层,它使用如下的接口方法:
IEnumerable<User> GetUsers(Func<User, bool> predicate);
因此,如果我想要给定角色中的所有用户,我可以这样做:
var plebs = GetUsers(u => u.Roles.Contains(plebRole));
现在我想通过WCF接口公开这种任何过滤器可以满足的想法。非.Net客户端需要访问WCF api,因此我想使用(相对)简单类型。
我有一个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方法之前,代码并没有真正发臭。现在确实如此。我该如何解决?
答案 0 :(得分:2)
如果你想超级想象,可以使用System.Linq.Expressions.Expression类根据传入的过滤器动态构建谓词。您知道要搜索的类型,因此您需要做的就是使用Filter.Property create a property expression,然后使用Filter.Value进行常量表达式。使用它们来构成一个相等的表达式,你就在终点线附近。
习惯于编写表达式可能会很麻烦,但是调试器非常有用,并且会在您编写表达式时向您显示表达式的代码,因此请深入研究并试用它!
答案 1 :(得分:1)
绝对没办法你可以通过网络获得Func<User, bool>
。 此表达式已存储并将被jitted并将存在于客户端世界中。
请记住,您基本上要做的是使用u => u.Roles.Contains(plebRole)
编译匿名客户端函数。因此,您将获得一些用户,您将在稍后在客户端进行过滤。