【问题标题】:Create linq-statement with dynamic components使用动态组件创建 linq 语句
【发布时间】:2014-01-09 03:46:01
【问题描述】:

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

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 语句?

【问题讨论】:

  • 好吧,您可以先将((x != null) &amp;&amp; !x.Trim().Equals(String.Empty)) 替换为!string.IsNullOrWhitespace(x)
  • 你可以创建一个方法来构建一个 Func&lt;T, bool&gt; 。但首先要做的是使用string.IsNullOrWhiteSpace
  • @user1567896 如果没有一个参数为空怎么办。
  • 我已经编辑了我的帖子。我正在使用.net3.5,所以我没有方法isNullOrWhiteSpace,但我将代码更改为IsNullOrEmpty。 @Suraj:然后使用所有三个参数过滤列表。
  • @user1567896 是的,所有三个过滤器都在起作用,但是最后返回的结果是你提供的返回 lstFoundPriceRows 这将是错误的,只看到你会得到的第三个过滤器结果,我不知道你的应用程序。逻辑,但我在这里看到的我认为它会给你错误的结果。

标签: c# linq .net-3.5


【解决方案1】:
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
    }
  }

【讨论】:

    【解决方案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();
    }
    

    由于没有更多的 if,您可以将这些语句合并为一个。

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

    【讨论】:

    • 在第三个版本中,为什么不打一个Where 电话?另外,OP 应该考虑返回IEnumerable&lt;PriceRow&gt;,这样你就不必在最后做.ToList()
    • @KrisVandermotten 因为我试图一步一步地到达那里,但你在我之前。
    • 第四个,在条件上使用&amp;&amp;运算符。
    • .Where(p =&gt; (string.IsNullOrWhitespace(dekorNr) || p.Artikelnummer.Contains(dekorNr))) &amp;&amp; (string.IsNullOrWhitespace(bezeichnung) || p.Bezeichnung.Contains(bezeichnung))) &amp;&amp; (string.IsNullOrWhitespace(hersteller || p.Lieferant.Contains(hersteller))) 有什么不正确的地方?
    • 已修复,还添加了一个更好的版本IsNullOrWhitespace,只是因为我们这里就是这样使用的。
    【解决方案3】:

    代码运行良好,但过于复杂。例如;如果你输入一个 deKorNr 和一个 hersteller 会发生什么?我不知道你是否可以用一个史诗般的 linq 语句来解决这个问题并让它变得不那么复杂......

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

    【讨论】:

    • 为什么要创建三个函数?这将发生所有三个参数都以有效值传递。如果我有三个方法,我必须连续调用所有三个。
    • 如果你的函数从起始帖子被调用,所有三个参数都填充了有效值,将会发生以下情况:你的三个函数将执行但只返回最后一个查询的结果......因此您需要添加大量 if/else 或修改代码以让结果集相互交叉。
    • 这正是我想要的:)。我只想要适合所有提供的参数的结果。因此,如果提供了三个参数,则所有参数都将用于过滤同一个列表。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-07-05
    • 2020-01-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-12-27
    相关资源
    最近更新 更多