使用动态组件创建linq语句

时间:2013-12-20 09:59:53

标签: c# linq .net-3.5

我有以下全功能方法,它根据输入参数返回一个列表(如果没有找到有效的输入则返回所有内容)

public List<PriceRow> GetABSPriceRows(string dekorNr, string bezeichnung, string hersteller)
{
    List<PriceRow> lstFoundPriceRows = _lstABSPriceRows; //_lstABSPriceRows is the source list

    if ((dekorNr != null) && !dekorNr.Trim().Equals(String.Empty))
        lstFoundPriceRows = lstFoundPriceRows.FindAll(p => p.Artikelnummer.Contains(dekorNr));

    if ((bezeichnung != null) && !bezeichnung.Trim().Equals(String.Empty))
        lstFoundPriceRows = lstFoundPriceRows.FindAll(p => p.Bezeichnung.Contains(bezeichnung));

    if ((hersteller != null) && !hersteller.Trim().Equals(String.Empty))
        lstFoundPriceRows = lstFoundPriceRows.FindAll(p => p.Lieferant.Contains(hersteller));

    return lstFoundPriceRows;
}

这三个参数可以是nullString.Empty,只应用于过滤源列表(如果它们不是nullString.Empty

正如我所说,代码工作正常,但我对它不满意;)。这似乎太复杂了。有没有办法只创建一个优雅的动态linq语句?

3 个答案:

答案 0 :(得分:2)

首先,您可以简化if条件:

public List<PriceRow> GetABSPriceRows(string dekorNr, string bezeichnung, string hersteller)
{
    List<PriceRow> lstFoundPriceRows = _lstABSPriceRows; //_lstABSPriceRows is the source list

    if (!string.IsNullOrWhitespace(dekorNr))
        lstFoundPriceRows = lstFoundPriceRows.FindAll(p => p.Artikelnummer.Contains(dekorNr));

    if (!string.IsNullOrWhitespace(bezeichnung))
        lstFoundPriceRows = lstFoundPriceRows.FindAll(p => p.Bezeichnung.Contains(bezeichnung));

    if (!string.IsNullOrWhitespace(hersteller))
        lstFoundPriceRows = lstFoundPriceRows.FindAll(p => p.Lieferant.Contains(hersteller));

    return lstFoundPriceRows;
}

其次,您可以使用where子句,该子句实际上不会对列表执行扫描(您现在正在执行3次扫描):

public List<PriceRow> GetABSPriceRows(string dekorNr, string bezeichnung, string hersteller)
{
    IEnumerable<PriceRow> lstFoundPriceRows = _lstABSPriceRows; //_lstABSPriceRows is the source list

    if (!string.IsNullOrWhitespace(dekorNr))
        lstFoundPriceRows = lstFoundPriceRows.Where(p => p.Artikelnummer.Contains(dekorNr));

    if (!string.IsNullOrWhitespace(bezeichnung))
        lstFoundPriceRows = lstFoundPriceRows.Where(p => p.Bezeichnung.Contains(bezeichnung));

    if (!string.IsNullOrWhitespace(hersteller))
        lstFoundPriceRows = lstFoundPriceRows.Where(p => p.Lieferant.Contains(hersteller));

    return lstFoundPriceRows.ToList();
}

从现在开始你正在进行一次扫描,你可以在Where谓词中移动条件:

public List<PriceRow> GetABSPriceRows(string dekorNr, string bezeichnung, string hersteller)
{
    IEnumerable<PriceRow> lstFoundPriceRows = _lstABSPriceRows; //_lstABSPriceRows is the source list

    lstFoundPriceRows = lstFoundPriceRows.Where(p => string.IsNullOrWhitespace(dekorNr) || p.Artikelnummer.Contains(dekorNr));

    lstFoundPriceRows = lstFoundPriceRows.Where(p => string.IsNullOrWhitespace(bezeichnung) || p.Bezeichnung.Contains(bezeichnung));

    lstFoundPriceRows = lstFoundPriceRows.Where(p => string.IsNullOrWhitespace(hersteller) || p.Lieferant.Contains(hersteller));

    return lstFoundPriceRows.ToList();
}

由于您没有ifs,您可以将这些语句组合成一个。

public List<PriceRow> GetABSPriceRows(string dekorNr, string bezeichnung, string hersteller)
{
    return _lstABSPriceRows
           .Where(p => string.IsNullOrWhitespace(dekorNr) || p.Artikelnummer.Contains(dekorNr))
           .Where(p => string.IsNullOrWhitespace(bezeichnung) || p.Bezeichnung.Contains(bezeichnung))
           .Where(p => string.IsNullOrWhitespace(hersteller) || p.Lieferant.Contains(hersteller))
           .ToList();
}

最后,我们可以将所有Where个谓词分组为一个(感谢@Kris):

public List<PriceRow> GetABSPriceRows(string dekorNr, string bezeichnung, string hersteller)
{
    return _lstABSPriceRows
           .Where(p => (string.IsNullOrWhitespace(dekorNr) || p.Artikelnummer.Contains(dekorNr)) && 
                       (string.IsNullOrWhitespace(bezeichnung) || p.Bezeichnung.Contains(bezeichnung)) &&
                       (string.IsNullOrWhitespace(hersteller) || p.Lieferant.Contains(hersteller)))
           .ToList();
}

您可以使用类似的扩展方法创建更简单(和3.5兼容)的IsNullOrWhitespace

public static bool IsNullOrWhitespace(this string s) 
{
   return (s == null || string.IsNullOrEmpty(s.Trim()));
}

随之而来的是表达变得更加简单:

public List<PriceRow> GetABSPriceRows(string dekorNr, string bezeichnung, string hersteller)
{
    return _lstABSPriceRows
           .Where(p => (dekorNr.IsNullOrWhitespace() || p.Artikelnummer.Contains(dekorNr)) && 
                       (bezeichnung.IsNullOrWhitespace() || p.Bezeichnung.Contains(bezeichnung)) &&
                       (hersteller.IsNullOrWhitespace() || p.Lieferant.Contains(hersteller)))
           .ToList();
}

答案 1 :(得分:0)

代码运行正常,但太复杂了。例如;如果您输入deKorNr和hersteller会发生什么?我不知道你是否可以用一个史诗般的linq语句解决这个问题并使其变得不那么复杂......

更好的解决方案是创建三个独立的函数,这些函数都有自己的逻辑。那么它首先不需要你原来的问题。

答案 2 :(得分:0)

public List<PriceRow> GetABSPriceRows(string dekorNr, string bezeichnung, string hersteller)
{
  List<PriceRow> lstFoundPriceRows = _lstABSPriceRows; //_lstABSPriceRows is the source list

    if (!string.IsNullOrWhitespace(dekorNr) || !string.IsNullOrWhitespace(bezeichnung)|| !string.IsNullOrWhitespace(hersteller) )
      {  
        lstFoundPriceRows = lstFoundPriceRows.Where (p => p.Artikelnummer.Contains(dekorNr) ||         
          p.Bezeichnung.Contains(bezeichnung)||p.Lieferant.Contains(hersteller)).ToList();   
       }    

    else
    {
     // Your query without filters
    }
  }