代码之家  ›  专栏  ›  技术社区  ›  rism

如何用表达式树表示所有有任何

  •  1
  • rism  · 技术社区  · 6 年前

    lambda可能表示为:

    class Tag 
    {
       public long TagId { get; set; }
    }
    
    class Taggable 
    {
       ICollection<Tag> Tags { get; set; }
    }
    
    ...
    
    IEnumerable<long> searchTags = new List<long>() { 1, 2, 3 };
    Func<Taggable, bool> filter = taggable => searchTags.All(qtag => taggable.Tags.Any(tag => tag.TagId == qtag));
    

    var tagParam = Expression.Parameter(typeof(Tag), "tag");    
    var taggableParam = Expression.Parameter(typeof(Taggable), "taggable");
    MemberExpression tagsProperty = Expression.Property(taggableParam, "Tags");
    ConstantExpression searchTagsConstant = Expression.Constant(searchTags);
    
    var containsCall = Expression.Call(
          typeof(Enumerable), "Contains",
          new[] { typeof(long) },
          searchTagsConstant,
          Expression.Property(tagParam, "TagID")
    );
    
    var anyCall = Expression.Call(
         typeof(Enumerable), "Any",
         new[] { typeof(Tag) },
         tagsProperty,
         Expression.Lambda(containsCall, tagParam)
    );
    
    // FAILS HERE
    var allCall = Expression.Call(
        typeof(Enumerable), "All",
        new[] { typeof(long) },
        searchTagsConstant,
        anyCall
    );
    

    类型“System.Linq.Enumerable”上的泛型方法“All”不兼容 如果方法不是泛型,则应提供。

    Enumerable.All<TSource, Func<TSource, bool>> searchTagsConstant anyCall

    1 回复  |  直到 6 年前
        1
  •  5
  •   Ivan Stoev    6 年前

    人们认为它会像 Enumerable.All<TSource, Func<TSource, bool>> searchTagsConstant anyCall

    不是lambda表达式( Func<TSource, bool> 这样的表达。

    IEnumerable<long> searchTags = new List<long>() { 1, 2, 3 };
    
    Expression<Func<Taggable, bool>> lambda = 
        taggable => searchTags.All(searchTag => taggable.Tags.Any(tag => tag.TagId == searchTag));
    

    无论如何,请注意,上面的表达式有3个lambda参数,而在您的尝试中只有2个。也没有 Contains

    构建上述表达式可以如下所示:

    var taggable = Expression.Parameter(typeof(Taggable), "taggable");
    var tag = Expression.Parameter(typeof(Tag), "tag");
    var searchTag = Expression.Parameter(typeof(long), "searchTag");
    // tag.TagId == searchTag
    var anyCondition = Expression.Equal(
        Expression.Property(tag, "TagId"),
        searchTag);
    // taggable.Tags.Any(tag => tag.TagId == searchTag)
    var anyCall = Expression.Call(
        typeof(Enumerable), nameof(Enumerable.Any), new[] { typeof(Tag) },
        Expression.Property(taggable, "Tags"), Expression.Lambda(anyCondition, tag));
    // searchTags.All(searchTag => taggable.Tags.Any(tag => tag.TagId == searchTag))
    var allCall = Expression.Call(
        typeof(Enumerable), nameof(Enumerable.All), new[] { typeof(long) },
        Expression.Constant(searchTags), Expression.Lambda(anyCall, searchTag));
    // taggable => searchTags.All(searchTag => taggable.Tags.Any(tag => tag.TagId == searchTag))
    var lambda = Expression.Lambda(allCall, taggable);