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

56
我正在浏览 .NET Framework Reference Source 的 .NET 源代码,只是为了好玩。但是发现了一些我不理解的东西。
有一个名为 Int32.cs 的文件,其中包含 Int32 类型的 C# 代码。这对我来说似乎有些奇怪。C# 编译器如何编译 Int32 类型的代码呢?
public struct Int32: IComparable, IFormattable, IConvertible {
    internal int m_value;

    // ... 
}

但是在C#中这不是违法的吗?如果int只是Int32的别名,那么它应该在编译时失败并出现Error CS0523错误:

类型为 'struct1' 的结构体成员 'struct2 field' 导致结构布局中的循环。

编译器有些魔力,还是我完全偏离了轨道?


10
到目前为止,我认为之前的答案忽略了真正的问题:“如果Int32只是int的别名,那么Int32类如何使用int?” - Tim M.
5
这里有关于完全相同问题的一些很好的讨论:http://social.msdn.microsoft.com/Forums/en-US/csharplanguage/thread/6d183671-2f42-4803-ac08-334d19708bc1/。 - mellamokb
2
同意@Tim的观点。这是一个好问题,可能应该在标题中提出。jure,我认为需要进行[编辑]。 - Cody Gray
5
内置类型就像魔法一样,必须如此,因为否则就会出现无穷无尽的嵌套。 - harold
6
然而,对于你的问题,答案非常简短。编译器中是否有特殊情况,可以允许System.Int32具有类型为System.Int32 的字段,这通常会导致错误?显然:是的。问题几乎可以自己回答;通常会出现错误,但对于 int 的极特殊情况却没有错误,因此编译器必须有一个特殊情况。而且确实存在这样的情况。 - Eric Lippert
显示剩余2条评论
2个回答

49

在C#中这不是违法的吗?如果“int”只是“Int32”的别名,那么它应该因为错误CS0523而无法编译。编译器中有些魔法吗?

是的,编译器故意抑制了这个错误。如果问题类型是内置类型,则完全跳过循环检查器。

通常这种情况是不允许的:

struct S { S s; int i; }
在这种情况下,S的大小是未定义的,因为无论S的大小是多少,它必须等于它自己加上一个int的大小。这样的大小是不存在的。
struct S { S s; }

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

struct Int32 { Int32 i; }

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

顺便说一下,C#编译器(以及CLR)如何确定一组结构类型何时成为循环的细节非常有趣。我打算在某个时候写一篇博客文章介绍这个问题。


5
当我的.NET源代码下载完成后,Int32是我打开的第一个文件。然后,第一行代码震惊了我。在.NET源代码中有一行不应该存在的代码。经过几秒钟的自我怀疑,我得出结论,你正在看的是Int结构体的代码,就像奇点一样,标准物理定律在这里不适用。所以我关闭了文件:)无论如何,期待你的博客文章,总是很愉快阅读它们。 - Jurica Smircic
1
我认为电子的内容是虚拟光子和虚拟电子-正电子对。同样,Int32应该定义为struct Int32 { byte byte1; byte byte2; byte3; byte4; } - Mark Cidade
1
我的正电子在哪里,这样我就可以将int转换为void! - Jurica Smircic
2
[StructLayout(LayoutKind.Auto, Size = 4)] struct S { S s; }会有信息来推断S的大小。但是如果没有特殊的语言和编译器支持,它并不感觉非常有用。 - Daniel A.A. Pelsmaeker
3
@EricLippert先生,您是否已经在博客上写了您提到的那篇文章?如果是,能否分享它的链接? - Soner from The Ottoman Empire
显示剩余3条评论

13

intInt32的别名,但您正在查看的Int32结构只是元数据,它不是一个真正的对象。可能只是为了给结构体指定适当的大小,才会有int m_value声明存在(这就是为什么允许它存在的原因)。

换句话说,编译器在某种程度上避免了这个问题。在MSDN论坛上有关于这个主题的讨论。

从讨论中,以下是所选答案的一句话引用,可以帮助尝试确定声明如何可能:

虽然类型包含一个整数m_value字段,但该字段从未被引用过。在每个支持的方法(CompareTo、ToString等)中,“this”都被使用。可能m_value字段仅存在于强制使结构具有适当大小。

我怀疑当编译器看到“int”时,它会将其转换为“对mscorlib.dll中System.Int32的引用,稍后解析”,并且由于正在构建mscorlib.dll,它最终会得到一个循环引用(但永远不会造成问题,因为m_value从未被使用)。如果这个假设是正确的,那么这个技巧只适用于特殊的编译器类型。

进一步阅读后,可以确定该结构仅仅是元数据,而不是一个真正的对象,因此它不受相同的递归定义限制。


我猜如果m_value被声明为Int32,编译会失败。在MSDN上有一个有趣的讨论。最后,这并不重要,但是值类型有一些奇怪的源代码 :) - Jurica Smircic
System.Int32 不是一个类,而是一个结构体。 - svick
1
我认为值得注意的是,在源代码中,m_value被广泛使用。然而,编译器的IL发射器有一个特殊规则,用父对象替换递归值类型中任何递归使用。当然,除了内置的那些之外,CLR将拒绝加载这样的递归值类型。 - Kevin Cathcart

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接