理解LINQ中的显式与隐式变量声明

本文关键字:变量 声明 LINQ 理解 | 更新日期: 2023-09-27 18:28:55

我有一个名为Item的类,我正在这个类上执行LINQ查询,但我注意到,当我尝试使用group运算符时:

我无法访问像key这样的IEnumarable接口扩展方法。

类似于:

       var groupByQuery =
            from item in items
            group item by item.ItemType[0];
        foreach (Item item in groupByQuery)
        {
            Console.WriteLine(item.Key);
            ...
        }

将产生错误:

`Error  1   'ProductCatalog.Item' does not contain a definition for 'Key' and no extension method 'Key' accepting a first argument of type 'ProductCatalog.Item' could be found (are you missing a using directive or an assembly reference?)`

我需要将其更改为:

foreach (var item in groupByQuery)
        {
            Console.WriteLine(item.Key);
            ...
        }

让它发挥作用。我只需要理解为什么会发生这种事。我脑子里有些东西告诉我这与Item的类型和Key返回的类型有关,但仅此而已

如果您简单地在item in groupByQuery行的item上使用IntelliSense和鼠标,您将看到这些类型的差异。

使用var item将使用组通过表达式生成的类型,即IGrouping<T, Item>(我在这里写T,因为我不知道ItemType[0]的类型)。

使用Item item会将其强制转换为Item,正如您所期望的那样。正如错误所描述的,类Item不实现Key。如果你选择这样做,你可以在你的类中显式地这样做,但这可能不是最好的方法。原因是,当您使用group by时,通常会返回一组Item,这与Item的单个实例不同(假设有多个ItemsItemType[0])。因此,您可能更喜欢使用实现IGrouping<T, Item>的新类(如ItemGroup),或者重新思考查询。

理解LINQ中的显式与隐式变量声明

组查询返回组的IEnumerable。一个组有一个Key和一个IEnumerable。所以,你的for循环可能是这样的:

foreach (var group in groupByQuery)
{
    Console.WriteLine(group.Key);
    foreach (var item in group)
    {
        Console.WriteLine("    {0}", item);
    }
}

那么你的问题更多的是关于foreach。CCD_ 24看起来相当于从第一个元素到最后一个元素(或break)的forwhile索引。对于您的foreach (Item item in groupByQuery),它似乎是这样开始的:

Item item = groupByQuery.ElementAt(0);

但是,它不会编译,因为组的类型不是Item。

关于foreach,不直观但完全有文档记录的地方是,编译器将其翻译为如下代码:

{
    E e = ((C)(x)).GetEnumerator();
    try {
        while (e.MoveNext()) {
            V v = (V)(T)e.Current;
            embedded-statement
        }
    }
    finally {
        … // Dispose e
    }
}

其中V是环路控制变量的给定或隐含类型。它执行一个强制转换,该转换可能在运行时失败,即使您更喜欢编译器错误。铸造将是我们对非通用IEnumerable的意图。实际上,对于IEnumerable<T>不存在foreach,它降级为对于IEnumerableforeach

如果你想知道原因,可以看看李柏特的博客。