【问题标题】:How To Use Yield Inside A Linq Query如何在 Linq 查询中使用 Yield
【发布时间】:2011-04-21 15:25:59
【问题描述】:

我有以下方法:

    public string GetDepartmentTitle(string DepartmentAbbreviation) {
        List<TaxonomyItem> Divisions = TaxonomyFromCMS.GetAllItems(DomainDataConstants.DivisionAndDepartment.TAXONOMY_ID);
        List<TaxonomyItem> Departments = new List<TaxonomyItem>();

        Divisions.ForEach(delegate(TaxonomyItem Division) {
            Departments.AddRange(Division.SubTaxonomyItems);
        });

        TaxonomyItem Result = (from d in Departments
                               where d.Name == DepartmentAbbreviation
                               select d).FirstOrDefault();

        return Result == null ? "" : Result.Title;
    }

它首先读取所有的部门(只有 3 个),但这些部门在它们下面有许多部门作为子分类项目。目前我逐步遍历每个部门并提取每个部门并将它们放在一个名为部门的列表中。然后我使用 Linq 搜索特定项目。

效果很好,但我很想跳过/使用获取子项目的第一步。我尝试了以下似乎不起作用的行:

TaxonomyItem Result = (from d in Departments.SubTaxonomyItems

然后,我可能会通过某种 lambda,其中包含一个包含 yeild 语句的 Departments.SubTaxonomyItems 的 foreach。这可能是诀窍,但我无法让它发挥作用。查看 yeild 声明,如果我做一些扩展方法,似乎有办法。但我想看看它是否可以内联完成,就像下面的伪代码:

    public string GetDepartmentTitle(string DepartmentAbbreviation) {
        List<TaxonomyItem> Divisions = TaxonomyFromCMS.GetAllItems(DomainDataConstants.DivisionAndDepartment.TAXONOMY_ID);

        TaxonomyItem Result = (from d in Divisions.ForEach(delegate(TaxonomyItem Division) {
                                 yeild return Divison.SubTaxonomyItems;
                               }) AS Dps
                               where Dps.Name == DepartmentAbbreviation
                               select Dps).FirstOrDefault();

        return Result == null ? "" : Result.Title;
    }

这可能是这种方式还是我没有看到的其他方式?不用扩展方法也能做到吗?

【问题讨论】:

    标签: c# linq yield


    【解决方案1】:

    首先,您只需在查询中添加另一个“来自”即可轻松解决您的问题:

    var query = from division in divisions
                from department in division.Departments
                where department.Name == whatever
                select department;
    

    这正是你所做的;它从每个部门中选出部门序列,并将所有这些序列粘合在一起,形成一个长的部门序列。

    这为您提供了“将一堆序列拼接在一起”场景的巧妙语法。但更一般地说,有时您会遇到这种情况:

    var bars = from foo in foos
               some complicated query logic here
               select foo.bar;
    var abcs = from bar in bars
               some other query logic here
               select bar.abc;
    

    并且您想弄清楚如何将其转换为单个查询。你可以这样做:

    var abcs = from bar in (
                   from foo in foos
                   some complicated query logic here
                   select foo.bar)
               some other query logic here
               select bar.abc;
    

    这是,或者你可以这样做:

    var abcs = from foo in foos
               some complicated query logic here
               select foo.bar into bar
               some other query logic here
               select bar.abc;
    

    这完全一样,但阅读起来更愉快。这种语法称为“查询延续”。

    回答您的具体问题:在匿名方法或 lambda 中放置“收益回报”是不合法的。这很不幸,因为它真的很有用。编译器为使匿名函数和迭代器块工作而执行的转换非常复杂,到目前为止,我们一直致力于让它们充分协同工作。 (也就是说,您可以将 lambda 放入迭代器块中,但不能将迭代器块放入 lambda 中。)我希望,但不保证,有一天我们将能够修复此代码并允许迭代器块 lambda。 (请记住,Eric 对未来语言功能的思考仅供娱乐。)

    【讨论】:

      【解决方案2】:

      看起来你只是想要这样的东西。

      public string GetDepartmentTitle(string DepartmentAbbreviation) {
          var items = TaxonomyFromCMS.GetAllItems(DomainDataConstants.DivisionAndDepartment.TAXONOMY_ID); 
          var result = items.SelectMany(item=>item.SubTaxonomyItems).FirstOrDefault(item=>item.Name == DepartmentAbbreviation);
          var text = result !=null  ? result.Title : String.Empty;
          return text;
      }
      

      【讨论】:

      • 该死的,你打败了我!
      【解决方案3】:

      Yield return 只能用于非常精选(双关语!)的位置,而 Linq 查询不是其中之一。幸运的是你在这里不需要它。

      var q = from division in Divisions
              from dps in division.SubTaxonomyItems
              where dps.Name == DepartmentAbbreviation
              select dps.Title;
      
      return q.FirstOrDefault() ?? String.Empty;
      

      【讨论】:

        【解决方案4】:

        为什么不直接做:

        var divisions = TaxonomyFromCMS.GetAllItems
                         (DomainDataConstants.DivisionAndDepartment.TAXONOMY_ID);
        
        var titles = from division in divisions
                     from deparment in division.SubTaxonomyItems
                     where deparment.Name == DepartmentAbbreviation
                     select deparment.Title;
        
        return titles.FirstorDefault() ?? "";
        

        【讨论】:

          【解决方案5】:

          这是您要找的 linq 吗?

          var Result = Divisions.SelectMany(d => d.SubTaxonomyItems).Where(subItem => subItem.Name == DepartmentAbbreviation).FirstOrDefault();
          

          【讨论】:

          • 您的代码中“subItem”的类型是什么?它似乎是一系列部门,但您将其视为一个部门。
          • 是 Division.SubTaxonomyItems 的一项。也许我误解了他的问题,请告诉我:) 谢谢。
          • 对。 “选择”返回项目序列序列。您假设 Select 返回一个 项目序列 - 它“扁平化”序列序列 - 但这不是 Select 所做的;这就是 SelectMany 所做的。在您的代码中,序列中的每个序列都将传递给“Where”,因此“subItem”将是一个项目序列,而一个项目序列没有名称。每个项目都有一个名称。
          • 有趣。我检查了差异,你是对的。 Select 返回项目组,而 SelectMany 从条件中选择单个项目。我会记住这一点的。谢谢。
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多