有趣的是,我在我的问题中被这个问题所困扰,为什么使用 ToList 时这个 Linq Cast 会失败?
Jon Skeet(当然)解释说我的问题是 C# 编译器,无论出于何种原因,认为它们永远不会是同一件事,并有助于将其优化为 false。但是,CLR确实让这种情况发生。转换为对象会引发编译器优化,因此它会通过 CLR。
他回答的相关部分:
即使在 C# 中不能直接将 byte[] 转换为 sbyte[],CLR 也允许:
var foo = new byte[] {246, 127};
// This produces a warning at compile-time, and the C# compiler "optimizes"
// to the constant "false"
Console.WriteLine(foo is sbyte[]);
object x = foo;
// Using object fools the C# compiler into really consulting the CLR... which
// allows the conversion, so this prints True
Console.WriteLine(x is sbyte[]);
Joel 在评论中问了一个有趣的问题,“这种行为是否由优化代码标志(/o
对编译器)控制?”
鉴于此代码:
static void Main(string[] args)
{
sbyte[] baz = new sbyte[0];
Console.WriteLine(baz is byte[]);
}
并用csc /o- Code.cs
(不要优化)编译,看来编译器无论如何都会优化它。生成的 IL:
IL_0000: nop
IL_0001: ldc.i4.0
IL_0002: newarr [mscorlib]System.SByte
IL_0007: stloc.0
IL_0008: ldc.i4.0
IL_0009: call void [mscorlib]System.Console::WriteLine(bool)
IL_000e: nop
IL_000f: ret
IL_0008 将 0(假)直接加载到堆栈上,然后调用WriteLine
IL_0009。所以不,优化标志没有任何区别。如果要咨询 CLR,isinst
则将使用该指令。从 IL_0008 开始,它可能看起来像这样:
IL_0008: ldloc.0
IL_0009: isinst uint8[]
IL_000e: ldnull
IL_000f: cgt.un
IL_0011: call void [mscorlib]System.Console::WriteLine(bool)
我同意优化器的行为。优化标志不应改变程序的行为。