【问题标题】:How does mscorlib's `System.Boolean` avoid struct layout cycles?mscorlib 的 `System.Boolean` 如何避免结构布局循环?
【发布时间】:2020-03-28 18:59:48
【问题描述】:

参考源网站上System.Boolean 的源代码指出struct Boolean 的实例仅包含一个bool 字段:private bool m_value

https://referencesource.microsoft.com/#mscorlib/system/boolean.cs,f1b135ff6c380b37

namespace System {

    using System;
    using System.Globalization;
    using System.Diagnostics.Contracts;

    [Serializable]
    [System.Runtime.InteropServices.ComVisible(true)]
    public struct Boolean : IComparable, IConvertible
#if GENERICS_WORK
        , IComparable<Boolean>,  IEquatable<Boolean>
#endif
    {
      private bool m_value;

      internal const int True = 1; 
      internal const int False = 0; 

      internal const String TrueLiteral  = "True";
      internal const String FalseLiteral = "False";

      public static readonly String TrueString  = TrueLiteral;
      public static readonly String FalseString = FalseLiteral;
}

但我注意到了……

  • boola C# language alias 对应于 System.Boolean
  • 类型是struct Boolean,它是一个值类型,意思是it cannot contain itself as a field
  • ...但是这段代码大概可以编译。
  • 我知道,当设置了-nostdlib 编译器选项时,您需要提供自己的基本 类型定义,例如System.StringSystem.Int32System.Exception - 这是唯一的区别。
  • 发布的源代码不包含其他特殊属性,如[MethodImpl( MethodImplOptions.InternalCall )]

那么这段代码是如何编译的呢?

【问题讨论】:

  • 这是一个很好的证明,常见的“它是一个别名”假设是一个破碎的心智模型。 bool 是 C# 语言中的关键字。编译器和运行时都有很多关于类型的内置知识,不需要 System.Boolean 的帮助。 mscorlib 中原始值类型的声明与该类型的装箱表示相匹配。

标签: c#


【解决方案1】:

简答:这是一种特殊情况,与类型装箱及其底层表示有关。这些类型对于编译器来说是众所周知的,因此与常规类型相比,运行时的核心部分和编译器/JIT 优化器对这些类型的处理略有不同。


由于这深埋在运行时实现中,我认为语言规范不会涉及具体的运行时实现细节。我不确定这是否是一个足够令人满意的答案,但我认为在这种特殊情况下,bool 类型仍然未装箱,因此作为结构的一部分作为原始值类型存在。

值类型的装箱和拆箱的语义是故意不透明的,以使使用语言更容易。在这种情况下,Boolean 结构本身似乎依赖于实现特定的装箱规则来实现实际语义,例如:

  // Determines whether two Boolean objects are equal.
  public override bool Equals (Object obj) {
    //If it's not a boolean, we're definitely not equal
    if (!(obj is Boolean)) {
      return false;
    }

    return (m_value==((Boolean)obj).m_value);
  }

我相信上面所说的,表示布尔类型的盒装结构首先进行类型检查,然后将其拆箱并直接比较内部 bool 值。与装箱类型(可能是标记指针或带有一些运行时类型信息的实际结构)不同,未装箱类型被视为实际数据。

我在内部相信,如果必须将 bool 装箱以传递为 System.Object(因为类型擦除或无法优化),您最终会得到类似于 true 的内容将值 1 框起来。

ldc.i4.1
box        [mscorlib]System.Boolean

因此,虽然在较高级别上 boolSystem.Boolean 看起来是相同的,并且可以进行类似的优化,但在运行时的这种特殊情况下,bool 的盒装版本和未盒装版本之间的区别直接暴露出来。类似地,未装箱的bool 不能与本质上是装箱类型的System.Object 进行比较。 This answer regarding the need for boxing/unboxing 更深入地解释了原理本身。

在托管语言中,当涉及到一些核心运行时特性时,运行时实现通常需要免除某些规则,这对于 Java 和其他基于 JVM 的语言来说当然是正确的。虽然我也不熟悉 CLR,但我认为这里也适用相同的原则。

虽然this question about 'bool' being a type alias for 'System.Boolean' 基本上涵盖了一般用例,但当接近运行时实现时,C# 的方言变得更像“特定于实现的 C#”,这可能会稍微改变规则。

【讨论】:

  • 为了您的见解,我对此表示赞同 - 但我不能将其标记为已接受的答案,因为它不具有权威性,抱歉 :(
猜你喜欢
  • 1970-01-01
  • 2011-03-14
  • 1970-01-01
  • 1970-01-01
  • 2014-07-27
  • 1970-01-01
  • 1970-01-01
  • 2020-03-02
  • 1970-01-01
相关资源
最近更新 更多