56

一直在浏览.NET Framework Reference Source的 .NET 源代码,只是为了好玩。并发现了一些我不明白的东西。

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

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

    // ... 
}

但这在 C# 中不是非法的吗?如果int只是 的别名 Int32,则它应该无法编译并出现错误 CS0523

“struct1”类型的结构成员“struct2 field”导致结构布局中的循环。

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

4

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)如何确定一组结构类型何时为循环的细节非常有趣。我会尝试在某个时候写一篇关于此的博客文章。

于 2013-04-22T19:31:12.380 回答
13

int是 的别名Int32,但Int32您正在查看的结构只是元数据,它不是真实对象。该int m_value声明可能只是为了给结构适当的大小,因为它实际上从未在其他任何地方引用(这就是允许它存在的原因)。

所以,换句话说,编译器可以避免这个问题。MSDN 论坛中有关于该主题的讨论。

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

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

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

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

于 2013-04-19T21:56:25.057 回答