【问题标题】:How to express All have Any with Expression Trees如何用表达式树表达 All have Any
【发布时间】:2018-06-23 16:29:36
【问题描述】:

对于给定的搜索标签过滤器,预期的结果是一个表达式,表示在给定的标签 ID 列表中具有所有标签的实体。

一个 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&lt;TSource, Func&lt;TSource, bool&gt;&gt; 应该满足 searchTagsConstantanyCall 的要求?

【问题讨论】:

  • 您能否修复您的代码示例以定义taggable 在您的行Expression.Property(taggable, "Tags"); 中是什么?
  • @Stand__Sure 这个答案只针对Any。问题是关于 All with Any。
  • 两者都是静态扩展。该方法应该适用于两者

标签: c# linq expression-trees


【解决方案1】:

人们认为它会起作用,因为 searchTagsConstantanyCall 应该满足 Enumerable.All&lt;TSource, Func&lt;TSource, bool&gt;&gt;

不。 anyCall 不是 lambda 表达式 (Func&lt;TSource, bool&gt;),只是这种表达式的潜在 主体

让我们从你的目标开始:

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);

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2010-09-24
    • 2019-11-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多