如果Int32只是int的别名,那么Int32类如何使用int?

jur*_*ure 56 c# compiler-construction internals

正在浏览.NET Framework Reference Source的 .NET源代码,只是为了它的乐趣.并找到了一些我不明白的东西.

有一个Int32.cs文件,其中包含Int32类型的C#代码.不知怎的,这对我来说似乎很奇怪.C#编译器如何编译Int32类型的代码?

public struct Int32: IComparable, IFormattable, IConvertible {
    internal int m_value;

    // ... 
}
Run Code Online (Sandbox Code Playgroud)

但这在C#中不是非法的吗?如果int只是别名 Int32,则无法使用错误CS0523进行编译:

'struct1'类型的struct成员'struct2字段'在struct布局中导致循环.

编译器中有一些魔法,还是我完全偏离轨道?

Eri*_*ert 48

在C#中这不是非法的吗?如果"int"只是"Int32"的别名,则无法使用错误CS0523进行编译.编译器中有一些魔力吗?

是; 错误是在编译器中故意抑制的.如果所讨论的类型是内置类型,则完全跳过循环检查器.

通常这种事情是非法的:

struct S { S s; int i; }
Run Code Online (Sandbox Code Playgroud)

在这种情况下,S的大小是未定义的,因为无论S的大小如何,它必须等于它自己加上int的大小.没有这样的尺寸.

struct S { S s; }
Run Code Online (Sandbox Code Playgroud)

在这种情况下,我们没有信息可以推断出S的大小.

struct Int32 { Int32 i; }
Run Code Online (Sandbox Code Playgroud)

但在这种情况下,编译器提前知道System.Int32四个字节,因为它是一种非常特殊的类型.

顺便提一下,C#编译器(以及,就此而言,CLR)如何确定一组结构类型何时是循环的细节非常有趣.我会尝试在某个时候写一篇博客文章.

  • Int32是我在.NET源代码下载完成后打开的第一个文件.然后第一线震惊了我..NET源代码中不存在一行代码.经过一段时间的自我怀疑,我得出结论,你所看到的是Int结构的代码,它就像奇点,物理的标准定律在这里不适用..所以我关闭了文件:)无论如何,看转到您的博客文章,总是乐于阅读它们. (5认同)
  • @EricLippert先生您是否已经在博客中写过您提到过的文章?如果是这样,你可以分享它的链接吗? (3认同)
  • `[StructLayout(LayoutKind.Auto,Size = 4)] struct S {S s; 如果没有特殊的语言和编译器支持,那么它将具有推断S的大小的信息. (2认同)

Joh*_*hey 13

int是一个别名Int32,但Int32您正在查看的结构只是元数据,它不是一个真正的对象.该int m_value声明有可能只给该结构的适当的大小,因为它从来没有真正的其他地方引用(这就是为什么它被允许在那里).

换句话说,编译器类可以将其保存为一个问题.MSDN论坛中有关于该主题的讨论.

从讨论中,这里是所选答案的引用,有助于确定声明是如何可能的:

虽然该类型包含整数m_value字段,但该字段永远不会被引用.在每种支持方法(CompareTo,ToString等)中,使用"this"代替.m_value字段可能仅存在以强制结构具有适当的大小.

我怀疑当编译器看到"int"时,它会将其转换为"mscorlib.dll中对System.Int32的引用,以后再解析",并且由于它正在构建mscorlib.dll,它最终会产生一个循环引用(但不是一个可以导致问题的因素,因为从未使用过m_value).如果这个假设是正确的,那么这个技巧只适用于特殊的编译器类型.

进一步阅读,可以确定结构只是元数据,而不是真实对象,因此它不受相同的递归定义限制的约束.