使用Linq过滤集合 - 如何重用相同的过滤器

时间:2013-05-29 15:26:00

标签: c# linq

我正在过滤一个集合,我执行两个相同但不同字段的过滤器。 必须有一种方法可以减少代码的重复吗? 检查是否已输入日期,以及是否在用户输入的截止日期之前。

    public override IList<Company> Search()
    {
        var list = CacheObjects.Subcontractors;

        this.ApplicationFormReturnedCheck(ref list);

        this.ApplicationFormSentCheck(ref list);
    }

    private void ApplicationFormReturnedCheck(ref IList<Subcontractor> list)
    {
        if (this.ApplicationFormNotReturnedFlag == true && this.ApplicationFormReturned != null)
        {
            list =
                list.Where(x => x.ApplicationFormReturned == null || x.ApplicationFormReturned < this.ApplicationFormReturned).ToList();
        }
        else if (this.ApplicationFormNotReturnedFlag == true)
        {
            list = list.Where(x => x.ApplicationFormReturned == null).ToList();
        }
        else if (this.ApplicationFormReturned != null)
        {
            list = list.Where(x => x.ApplicationFormReturned < this.ApplicationFormReturned).ToList();
        }
    }

    private void ApplicationFormSentCheck(ref IList<Subcontractor> list)
    {
        if (this.ApplicationFormNotSentFlag == true && this.ApplicationFormSent != null)
        {
            list =
                list.Where(x => x.ApplicationFormSent == null || x.ApplicationFormSent < this.ApplicationFormSent).ToList();
        }
        else if (this.ApplicationFormNotSentFlag == true)
        {
            list = list.Where(x => x.ApplicationFormSent == null).ToList();
        }
        else if (this.ApplicationFormSent != null)
        {
            list = list.Where(x => x.ApplicationFormSent < this.ApplicationFormSent).ToList();
        }
    }

2 个答案:

答案 0 :(得分:1)

我建议您可以做一些简单的事情,例如Func<Subcontractor,bool>覆盖您的各种场景。这是Func方法所需的Where类型

为了演示让我采用你的一种方法并告诉你如何:

private void ApplicationFormReturnedCheck(ref IList<Subcontractor> list)
{
    var isFormReturned = new Func<Subcontractor,bool>(
          x => x.ApplicationFormReturned != null);
    var isBeforeDate = new Func<Subcontractor,bool>(
          x => x.ApplicationFormReturned < this.ApplicationFormReturned);
    var isFormReturnedOrBeforeDate= new Func<Subcontractor,bool>(
          x => isFormReturned(x) || isFormReturnedBeforeDate(x));

    if (this.ApplicationFormNotReturnedFlag == true && this.ApplicationFormReturned != null)
    {
        list = list.Where(isFormReturnedOrBeforeDate).ToList();
    }
    else if (this.ApplicationFormNotReturnedFlag == true)
    {
        list = list.Where(isFormReturned).ToList();
    }
    else if (this.ApplicationFormReturned != null)
    {
        list = list.Where(isBeforeDate).ToList();
    }
}

您展示的另一种方法虽然具有类似的逻辑,但使用了一组不同的变量。 (ApplicationFormSent代替ApplicationFormReturned)。我看到它的方式你有两个选择

  1. 使用不同的变量名称
  2. 在另一种方法中复制上述内容
  3. 使用更复杂的方法,您可以在每个方法的范围之外使用这3个Func,并且能够区分要使用的变量(*Sent*Returned)。
  4. 上面的问题是,随着你的感知“重用”的增加,你的代码的可读性会下降。

    老实说,我发现原始代码没有重大问题!它清晰,非常简洁,很容易看出它在做什么。通过将所有这些逻辑包含在谓词中(可以想象在本课程的其他地方),你会使阅读更难以维护。

答案 1 :(得分:0)

可以使用Func(T, TResult)来封装常见的谓词方法。在您的情况下,由于您在过滤器中使用实例成员,因此需要在构造函数中初始化Func。例如:

private readonly Func<Subcontractor, bool> _pred;

public Subcontractor()
{
    _pred = x => x.ApplicationFormReturned == null || x.ApplicationFormReturned < this.ApplicationFormReturned;
}

private void ApplicationFormReturnedCheck( ref IList<Subcontractor> list )
{
    if( this.ApplicationFormNotReturnedFlag == true && this.ApplicationFormReturned != null )
    {
        list = list.Where( _pred ).ToList();
    }
    else if( this.ApplicationFormNotReturnedFlag == true )
    {
        list = list.Where( x => x.ApplicationFormReturned == null ).ToList();
    }
    else if( this.ApplicationFormReturned != null )
    {
        list = list.Where( x => x.ApplicationFormReturned < this.ApplicationFormReturned ).ToList();
    }
}