【问题标题】:Linq Query to IEnumerable<T> Extension MethodLinq 查询到 IEnumerable<T> 扩展方法
【发布时间】:2011-01-01 16:27:50
【问题描述】:

考虑一下,

     class Item
     { 
        public string ID { get; set;}
        public string Description { get; set; }
     }

     class SaleItem
     { 
        public string ID { get; set;}
        public string Discount { get; set; }
     }


     var itemsToRemoved = (List<Item>)ViewState["ItemsToRemove"];
     // get only rows of ID
     var query = from i in itemsToRemoved select i.ID;

     var saleItems= (List<SaleItem>)ViewState["SaleItems"];
     foreach (string s in query.ToArray())
     {
            saleItems.RemoveItem(s);
     }

如何使用 IEnumerable/List 扩展方法编写此 LINQ 短语

  // get only rows of ID
   var query = from i in items select i.ID;

提前致谢。

【问题讨论】:

    标签: c# linq


    【解决方案1】:

    这很简单:

    var query = items.Select(i => i.ID);
    

    select 子句始终对应于对Select 的调用。其他一些运算符最终会得到一个相当复杂的扩展:) 如果你努力工作,你可以让编译器做一些very odd stuff...

    您可以在C# specification(v3 或 v4)的第 7.16 节中找到此查询表达式翻译和其他查询表达式翻译的所有详细信息。

    &lt;plug&gt; 如果你真的想的话,你也可以购买C# in Depth, 2nd edition并阅读第11章:)&lt;/plug&gt;

    【讨论】:

    • 感谢乔恩。我还有一个问题,哪个更快,是枚举器的扩展方法还是 LInQ 查询?
    • @CsharpNoob:区别只存在于源代码中。编译后的形式一模一样
    • 阅读你的博文我不明白为什么它真的那么奇怪......你必须接受的是,select-clause 将在 in-clause 中指定的“事物”上调用 Select 方法.只要它有一个 Select 方法,编译器就不会关心它是什么。
    • @Pauli:它不一定是 Select method - 它可以是委托类型的属性或字段。你不觉得这有点有点奇怪吗?同样,源可以只是一个类型的名称(以便调用静态方法)这一事实对我来说似乎很奇怪。
    • 定义一个函数到一个属性/字段基本上使它可以使用语法 Select() 调用,欺骗调用者使它看起来像一个方法,所以我不觉得它很奇怪。如果编译器不关心我们在子句中指定的东西,委托,变量类型都是可以接受的,只要它们有一个 Select 方法或名为 Select 类型的 Func 属性/字段.
    【解决方案2】:

    你可以用这个:

    var query = items.Select(i => i.ID);
    

    其他几点:

    这里你不需要打电话给ToArray

    foreach (string s in query.ToArray())
    

    此外,如果您的列表很大并且您要删除很多项目,您可能希望使用List.RemoveAll 而不是迭代。每次从列表中删除一个项目时,所有其他项目都必须移动以填补空白。如果您使用RemoveAll,则只需在最后执行一次,而不是为每个删除的项目执行一次。

    List<Item> itemsToRemove = (List<Item>)ViewState["ItemsToRemove"];
    HashSet<string> itemIds = new HashSet<string>(itemsToRemove.Select(s => s.ID));
    saleItems.RemoveAll(c => itemIds.Contains(c.ID));
    

    【讨论】:

    • @CSharpNoob:你能用 hashSet.Contains 作为你的谓词吗?
    • @CSharpNoob:RemoveAll 不需要传递项目的实例 - 它只需要传递一个谓词(函数)来决定是否应该删除每个项目。
    • @CSharpNoob:看到这个非常相似的问题:stackoverflow.com/questions/4312437/…
    • 哇就像一个魅力:HashSet itemIds = new HashSet(((List)ViewState["ItemsToRemove"]).Select(s => s.ID) ); saleItems.RemoveAll(c => itemIds.Contains(c.ID));
    • @CSharpNoob:是的,完全正确。我已将您的代码添加到我的答案中并稍微重写以使其更具可读性。希望没关系。
    【解决方案3】:
    public static class ItemCollectionExtensions
    {
        public static IEnumerable<int> GetItemIds(this List<Item> list)
        {
            return list.Select(i => i.ID);
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-11-06
      • 1970-01-01
      • 1970-01-01
      • 2019-03-17
      • 2017-01-30
      • 2011-07-28
      • 2018-12-24
      • 1970-01-01
      相关资源
      最近更新 更多