【问题标题】:If Int32 is just an alias for int, how can the Int32 class use an int?如果 Int32 只是 int 的别名,那么 Int32 类如何使用 int?
【发布时间】:2013-04-19 21:35:13
【问题描述】:

一直在浏览.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”导致结构布局出现循环。

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

【问题讨论】:

  • 我认为到目前为止的答案都缺少真正的问题:“如果 Int32 只是 int 的别名,那么 Int32 类如何使用 @987654332 @?”
  • 这里有一些关于完全相同的问题的很好的讨论:social.msdn.microsoft.com/Forums/en-US/csharplanguage/thread/…
  • 同意@Tim。这是一个很好的问题,可能是标题中应该问的问题。法律上,我认为edit 是合适的。
  • 内置类型很神奇。他们必须是 - 否则它会一直是海龟。
  • 但是,您的问题的答案非常简短。编译器中是否有特殊情况允许System.Int32 具有System.Int32 类型的字段,这通常是错误的?显然:是的。这个问题实际上回答了自己;通常会出现错误,对于 int 的极端特殊情况没有错误,因此编译器中必须存在特殊情况。还有。

标签: c# compiler-construction internals


【解决方案1】:

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

【讨论】:

  • Int32 是我在 .NET 源代码下载完成后打开的第一个文件。然后第一行让我震惊。 .NET 源代码中有一行不应该存在的代码。经过片刻的自我怀疑,我得出了结论,您正在查看的是 Int 结构的代码,就像奇点一样,标准物理定律不适用于这里.. 所以我关闭了文件:) 无论如何,看转发到您的博客文章,总是很高兴阅读它们。
  • 我认为电子的内容是虚光子和虚电子-正电子对。 (同样,一个 Int32 应该定义为struct Int32 { byte byte1; byte byte2; byte byte3; byte byte4; }
  • 我的正电子在哪里,所以我可以将 int 转换为 void!
  • [StructLayout(LayoutKind.Auto, Size = 4)] struct S { S s; } 会有信息来推断 S 的大小。但是如果没有特殊的语言和编译器支持,它感觉不是很有用。
  • @EricLippert 先生,您在您的博客上写过您提到的文章吗?如果是这样,你能分享它的链接吗?
【解决方案2】:

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

因此,换句话说,编译器可以避免这个问题。有话题讨论in the MSDN Forums

从讨论中,这里引用了所选答案的引用,有助于尝试确定声明的可能性:

虽然该类型确实包含一个整数 m_value 字段 - 字段永远不会被引用。在每个支持方法(CompareTo, ToString 等),而是使用“this”。有可能是 m_value 字段仅存在以强制结构具有 大小合适。

我怀疑当编译器看到“int”时,它会将其翻译成“a 引用 mscorlib.dll 中的 System.Int32,稍后解决”,以及 由于它正在构建 mscorlib.dll,因此它确实以周期性结束 参考(但不是可能导致问题的参考,因为 m_value 从未使用过)。如果这个假设是正确的,那么这个技巧将 仅适用于特殊的编译器类型。

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

【讨论】:

  • 我猜如果 m_value 被声明为 Int32 编译会失败。 MSDN 上的有趣讨论。最后,这确实无关紧要,但是值类型有一些奇怪的源代码:)
  • System.Int32 不是一个类,它是一个结构体。
  • 我认为值得注意的是,m_value在源代码中使用,实际上相当多。然而,编译器的 IL 发射器有一个特殊的规则,它将递归值类型中递归的任何使用替换为父对象的使用。当然,CLR 会拒绝不加载这样的递归值类型,内置的除外。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2010-09-08
  • 2015-02-10
  • 2013-01-09
  • 2012-08-14
  • 2010-11-13
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多