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

时间:2014-11-02 04:14:18

标签: c# linq

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

我无法访问IEnumarablekey接口扩展方法。

类似的东西:

       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类型的返回有关,但这就是它。

2 个答案:

答案 0 :(得分:2)

如果您只是使用item行的IntelliSense和鼠标悬停item in groupByQuery,您会看到这些类型的差异。

使用var item将使用由表达式生成的类型,IGrouping<T, Item>(我在此处写了T,因为我不知道ItemType[0]的类型)。

使用Item item会将其转换为Item,如您所料。如错误所述,类Item未实现Key。如果您选择这样做,您可以在班级中明确地执行此操作,但这可能不是最好的方法。原因是,通常当您使用group by时,您将返回一组Item,这与Item的单个实例不同(假设将有多个Items ItemType[0])。因此,您可能更喜欢使用实现ItemGroup的新类(例如IGrouping<T, Item>)或重新考虑查询。

答案 1 :(得分:0)

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

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

您的问题更多是关于foreachforeach似乎等同于从第一个元素到最后一个元素(或for)的whilebreak索引。使用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的意图。实际上,foreach没有IEnumerable<T>foreach的降级为IEnumerable

如果您想知道原因,请参阅Eric Lippert's blog