nan*_*nan 7 c# foreach nullable
我有一个可以为空的int集合.
为什么编译器允许迭代变量的类型为int而不是int??
List<int?> nullableInts = new List<int?>{1,2,3,null};
List<int> normalInts = new List<int>();
//Runtime exception when encounter null value
//Why not compilation exception?
foreach (int i in nullableInts)
{
//do sth
}
Run Code Online (Sandbox Code Playgroud)
当然我应该注意我迭代的内容但如果编译器训斥我会很好:)就像这里:
foreach (bool i in collection)
{
// do sth
}
//Error 1 Cannot convert type 'int' to 'bool'
Run Code Online (Sandbox Code Playgroud)
好的,最初我说“编译器将强制转换添加到foreach循环中”。这并不严格准确:它并不总是添加强制转换。这就是真正发生的事情。
首先,当你有这个foreach循环时:
foreach (int x in collection)
{
}
Run Code Online (Sandbox Code Playgroud)
...这里是编译器创建内容的基本轮廓(伪 C# 语言):
int x;
[object] e;
try
{
e = collection.GetEnumerator();
while (e.MoveNext())
{
x = [cast if possible]e.Current;
}
}
finally
{
[dispose of e if necessary]
}
Run Code Online (Sandbox Code Playgroud)
什么?我听到你说。你是什么意思[object]?”
这就是我的意思。该foreach循环实际上不需要任何接口,这意味着它实际上有点神奇。它只要求被枚举的对象类型公开一个GetEnumerator方法,而该方法又必须提供某种类型的实例,该实例提供 aMoveNext和 aCurrent属性。
所以我这么写是[object]因为 的类型e不一定必须是 的实现IEnumerator<int>,甚至IEnumerator- 这也意味着它不一定必须实现IDisposable(因此是该[dispose if necessary]部分)。
为了回答这个问题,我们关心的代码部分是我编写的部分[cast if possible]。显然,由于编译器不需要实际的IEnumerator<T>或IEnumerator实现,因此不能将 的类型e.Current假定为T或object介于两者之间的任何类型。e.Current相反,编译器根据GetEnumerator编译时返回的类型来确定 的类型。然后会发生以下情况:
x在上面的示例中),则使用直接赋值。e.Current到 类型的合法转换x),则插入转换。因此,在枚举 a 的场景中List<int?>,我们进入步骤 2,编译器会看到该List<int?>.Enumerator类型的Current属性属于类型int?,可以显式转换为int。
因此该行可以编译为等价的:
x = (int)e.Current;
Run Code Online (Sandbox Code Playgroud)
现在,explicit操作员是什么样子的Nullable<int>?
根据反射镜:
public static explicit operator T(T? value)
{
return value.Value;
}
Run Code Online (Sandbox Code Playgroud)
因此,据我所知,Kent 描述的行为(int)e.Current只是一种编译器优化:显式强制转换是内联的。
作为对您问题的一般回答,我坚持我的主张,即编译器会foreach在需要时在循环中插入强制转换。
编译器会自动在foreach循环中需要的地方插入强制转换,原因很简单,在泛型之前没有IEnumerable<T>接口,只有IEnumerable*。该IEnumerable接口公开一个IEnumerator,而后者又提供对Currenttype 属性的访问object。
因此,除非编译器为您执行强制转换,否则在过去,您可以使用的唯一方法foreach是使用类型的局部变量object,这显然会很糟糕。
*实际上,foreach根本不需要任何接口——只需要方法和带有 a和 a 的GetEnumerator附带类型。MoveNextCurrent