gpt4 book ai didi

c# - 我应该如何在多个 LINQ-where 子句之间共享过滤逻辑?

转载 作者:太空狗 更新时间:2023-10-29 21:56:57 24 4
gpt4 key购买 nike

A成为拥有某些属性(property)的类(class)Hello .我想过滤 A 的集合此属性在许多地方的实例。因此我会在某处创建一个 Expression<Func<A, bool>> 类型的静态成员它表示过滤谓词,我在所有进行过滤的地方都使用它。 (这个谓词将由 ORM 转换为一些具体的特定于 DB 的表达式。)

下一步。存在一个类 B具有 A 类型的属性.我想过滤 B 的集合实例使用与第一种情况相同的逻辑(通过类 Hello 的属性 A)。

问题。实现这一点并减少代码重复的最正确方法是什么?

我的建议。添加三样东西:1)接口(interface)IWithA具有 A 类型的属性, 2) 类 WithA<T>实现这个接口(interface) IWithA并提供 T 类型的属性, 3) Expression<Func<IWithA, bool>> 类型的一些静态属性实现过滤逻辑。演示代码如下。

    public static void Main() {
var listOfAs = new List<A>().AsQueryable();
var query0 = listOfAs
.Select(a => new WithA<A> {
A = a,
Smth = a,
})
.Where(Filter);
var listOfBs = new List<B>().AsQueryable();
var query1 = listOfBs
.Select(b => new WithA<B> {
A = b.A,
Smth = b,
})
.Where(Filter);
}

private class A {
public int Hello { get; set; }
}

private class B {
public A A { get; set; }
}

private interface IWithA {
A A { get; set; }
}

private class WithA<T> : IWithA {
public A A { get; set; }
public T Smth { get; set; }
}

private static readonly Expression<Func<IWithA, bool>> Filter = a => a.A.Hello > 0;

这种方法的问题:1) 必须总是生成 Select(x => new WithA<X> { ... }) , 2) ORM 可能不支持这个。

关于答案。我对接受的答案(由 Ivan Stoev)感到满意。我认为这是最好的方法。查看 Mihail Stancescu 的建议也很有帮助(请参阅问题评论)。我还是不明白user853710的回答;也许它也很有用。

最佳答案

我会创建并使用一个辅助函数来转换原始的 Expression<A, bool>Expression<B, bool>使用 System.Linq.Expressions像这样

public static class ExpressionUtils
{
public static Expression<Func<TTarget, bool>> ConvertTo<TSource, TTarget>(this Expression<Func<TSource, bool>> source, Expression<Func<TTarget, TSource>> sourceSelector)
{
var body = new ParameterExpressionReplacer { source = source.Parameters[0], target = sourceSelector.Body }.Visit(source.Body);
var lambda = Expression.Lambda<Func<TTarget, bool>>(body, sourceSelector.Parameters);
return lambda;
}

class ParameterExpressionReplacer : ExpressionVisitor
{
public ParameterExpression source;
public Expression target;
protected override Expression VisitParameter(ParameterExpression node)
{
return node == source ? target : base.VisitParameter(node);
}
}
}

示例用法

Expression<Func<A, bool>> filterA = item => item.Hello == 2; // The original logic
var filterB = filterA.ConvertTo((B b) => b.A);

这种方法不需要对您的实体模型进行任何更改。当然,如果你愿意,你可以将过滤器缓存在各个类的静态属性中,但原则仍然是在一个地方编写逻辑,然后在其他地方使用转换。

关于c# - 我应该如何在多个 LINQ-where 子句之间共享过滤逻辑?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34917946/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com