理解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
的单个实例不同(假设有多个Items
和ItemType[0]
)。因此,您可能更喜欢使用实现IGrouping<T, Item>
的新类(如ItemGroup
),或者重新思考查询。
组查询返回组的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
)的for
或while
索引。对于您的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
,它降级为对于IEnumerable
的foreach
。
如果你想知道原因,可以看看李柏特的博客。