Como o `System.Boolean` do mscorlib evita os ciclos de layout da estrutura?

10

O código-fonte para System.Booleanno site da fonte de referência afirma que as instâncias do struct Booleancontêm apenas um único boolcampo: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;
}

Mas eu notei que ...

  • boolé um alias do idioma C # paraSystem.Boolean .
  • O tipo é struct Booleanum tipo de valor, o que significa que não pode se conter como um campo .
  • ... no entanto, este código provavelmente compila.
  • Eu entendo que quando a -nostdlibopção do compilador está definida, você precisa fornecer suas próprias essencial definições de tipo de gosto System.String, System.Int32,System.Exception - essa é a única diferença.
  • O código-fonte publicado não contém outros atributos especiais, como [MethodImpl( MethodImplOptions.InternalCall )].

Então, como esse código é compilado?

Dai
fonte
11
É uma demonstração decente de que a suposição comum de "é um pseudônimo" é um modelo mental quebrado. boolé uma palavra - chave na linguagem C #. Tanto o compilador quanto o tempo de execução têm muito conhecimento interno sobre o tipo e não precisam da ajuda do System.Boolean. As declarações em mscorlib para os tipos de valor primitivo correspondem à representação em caixa do tipo.
Hans Passant

Respostas:

3

Resposta curta : é um caso especial, relacionado ao boxe de tipo e sua representação subjacente. Esses tipos são bem conhecidos pelo compilador e, como tal, são tratados de maneira um pouco diferente pelas partes principais do tempo de execução e pelo otimizador do compilador / JIT em comparação aos tipos regulares.


Como isso está enterrado profundamente na implementação do tempo de execução, eu presumo que a especificação da linguagem não entre em detalhes específicos da implementação do tempo de execução. Não tenho certeza se essa é uma resposta satisfatória o suficiente, mas acho que, nesse caso em particular, o booltipo permanece sem caixa e, portanto, existe como um tipo de valor bruto como parte da estrutura.

A semântica do boxe e do unboxing dos tipos de valor é intencionalmente opaca para facilitar o uso da linguagem. Nesse caso, a Booleanprópria estrutura parece depender de regras de boxe específicas da implementação para implementar a semântica real, como:

  // 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);
  }

Eu acredito no exposto acima, uma estrutura em caixa representando um tipo booleano é primeiro verificada, seguida por ser desmarcada e o boolvalor interno diretamente comparado. Diferentemente de um tipo de caixa, que pode ser um ponteiro marcado ou uma estrutura real com algumas informações sobre o tipo de tempo de execução, os tipos sem caixa são tratados como dados reais.

Creio que internamente, se um bool tivesse que ser encaixotado para ser passado como System.Object(por causa do apagamento de tipo ou onde nenhuma otimização seria possível), você terminaria com algo ao longo das linhas para o truequal caixas o valor 1.

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

Portanto, embora em um nível alto boole System.Booleanpareçam idênticos e possam ser otimizados de maneira semelhante, nesse caso específico durante o tempo de execução, as distinções entre as versões em caixa e em caixa boolsão expostas diretamente. Da mesma forma, um boolnão- caixa não pode ser comparado ao System.Objectqual é inerentemente um tipo de caixa. Esta resposta sobre a necessidade de boxe / unboxing é muito mais aprofundada na explicação do próprio princípio.

Em linguagens gerenciadas, as implementações de tempo de execução geralmente precisam ser isentas de certas regras quando se trata de alguns recursos principais de tempo de execução, isso certamente é verdade para Java e outras linguagens baseadas em JVM. Embora eu também não esteja familiarizado com o CLR, acho que o mesmo princípio se aplica aqui.

Embora essa pergunta sobre 'bool' seja um alias de tipo para 'System.Boolean', cubra essencialmente casos de uso geral, ao se aproximar da implementação em tempo de execução, o dialeto do C # se torna mais como "C # específico da implementação", o que pode alterar um pouco as regras .

Kristina Brooks
fonte
I upvoted isso para o seu discernimento -, mas não posso marcar este como a resposta aceita, porque não é autorizada, sorry :(
Dai