如何拦截Linq过滤器

时间:2015-08-16 18:42:21

标签: linq filter pipe

在LINQ to Objects中,无论如何都要确定哪些实体/对象在每个过滤器上合格/不合格?

例如)假设我有一个名为“产品”(Id,名称)的实体,如果我将100个产品输入Linq查询,其中有5个“where”条件并获得20个产品作为输出。

有没有办法确定哪个产品被过滤了哪个条件?

2 个答案:

答案 0 :(得分:2)

这可能是一般化的,但你可以做到这一点。我只是没有看到它的用例。

使用ToLookup()对查询进行分区。 "取消资格"项目将归入false群组,您可以继续使用true群组进行查询。

如,

var numbers = Enumerable.Range(0, 100);
var p1 = numbers.ToLookup(n1 => n1 < 50); 
// p1[false] -> [ 50, 51, 52, ... ]
var p2 = p1[true].ToLookup(n2 => n2 % 2 == 0);
// p2[false] -> [ 1, 3, 5, 7, ... ]
var p3 = p2[true]... // and so on

答案 1 :(得分:0)

虽然到目前为止每个人都向您展示了如何做出明显的事情,即将您的数据分组为符合一个条件的块,但是没有人解决您实际要求的问题

  

确定哪个产品已过滤哪个条件

棘手的问题是如何记录where条件?

执行此操作似乎微不足道,但您将失败,因为您将无法获取所使用的Func对象的字符串表示形式。它是一个委托,即编译代码,您必须在运行时对其进行反向工程以获取源代码。这本身就足够了,但是如果编译器选择优化你失去的代码。

只有当您愿意创建自己的扩展方法(使用表达式而不是Func s)时,您才能记录where条件,因为表达式由在运行时很容易被“ToString-ed”的标记组成。

例如:

public static IEnumerable<T> WhereEx<T>(this IEnumerable<T> sequence, Expression<Func<T, bool>> condition)
{
    var logString = condition.Body.ToString();
    foreach (T item in sequence.Where(condition.Compile()))
    {
        yield return item;
        // logging hook here, this one simply dumps in Linqpad.
        string.Format("Item '{0}' meets '{1}'", item, logString).Dump();
    }
}

现在你真的拦截了过滤器。但是你不知道在代码中应用过滤器的位置。如果你还想记录堆栈帧,性能可能会成为一个问题(反思!),因为每次编译表达式都已经面临压力。然后,日志记录应该是涉及线程安全日志记录队列的异步操作。