序列化wcf的谓词

时间:2010-12-02 13:59:35

标签: c# wcf generics predicate

我有一个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方法之前,代码并没有真正发臭。现在确实如此。我该如何解决?

2 个答案:

答案 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)编译匿名客户端函数。因此,您将获得一些用户,您将在稍后在客户端进行过滤。