W jaki sposób system.Boolean w mscorlib unika cykli układania struktur?

10

Kod System.Booleanźródłowy w witrynie Source Source podaje, że instancje struct Booleanzawierają tylko jedno boolpole 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;
}

Ale zauważyłem, że ...

  • boolto alias języka C # dla System.Boolean.
  • Typ jest typem struct Booleanwartości, co oznacza, że nie może się zawierać jako pole .
  • ... ale ten kod prawdopodobnie się kompiluje.
  • Rozumiem, że po ustawieniu -nostdlibopcji kompilatora musisz podać własne podstawowe definicje typu System.String, takie jak System.Int32, System.Exception- to jedyna różnica.
  • Opublikowany kod źródłowy nie zawiera innych specjalnych atrybutów, takich jak [MethodImpl( MethodImplOptions.InternalCall )].

Jak się kompiluje ten kod?

Dai
źródło
1
To przyzwoita demonstracja, że ​​powszechne założenie „to alias” jest zepsutym modelem mentalnym. booljest słowem kluczowym w języku C #. Zarówno kompilator, jak i środowisko wykonawcze mają dużo wbudowanej wiedzy o typie i nie potrzebują pomocy z System.Boolean. Deklaracje w mscorlib dla pierwotnych typów wartości są zgodne z ramkową reprezentacją typu.
Hans Passant,

Odpowiedzi:

3

Krótka odpowiedź : jest to szczególny przypadek związany z boksowaniem typów i ich podstawową reprezentacją. Te typy są dobrze znane kompilatorowi i jako takie są traktowane nieco inaczej przez podstawowe części środowiska wykonawczego i optymalizator kompilatora / JIT w porównaniu z typowymi typami.


Ponieważ jest to zakopane głęboko w implementacji środowiska wykonawczego, przypuszczam, że specyfikacja języka nie wchodziłaby w szczegółowe szczegóły implementacji środowiska wykonawczego. Nie jestem pewien, czy jest to wystarczająca odpowiedź, ale myślę, że w tym konkretnym przypadku booltyp pozostaje rozpakowany, a zatem istnieje jako typ wartości surowej jako część struktury.

Semantyka boksowania i rozpakowywania typów wartości jest celowo nieprzejrzysta, aby ułatwić korzystanie z języka. W tym przypadku Booleanwydaje się, że sama struktura opiera się na specyficznych dla implementacji regułach boksu w celu implementacji rzeczywistej semantyki, takiej jak:

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

Wierzę w powyższe, że struktura pudełkowa reprezentująca typ boolowski jest najpierw sprawdzana pod względem typu, następnie jest rozpakowywana, a wewnętrzna boolwartość jest bezpośrednio porównywana. W odróżnieniu od typu pudełkowego, który może być oznakowanym wskaźnikiem lub rzeczywistą strukturą z pewnymi informacjami o typie środowiska wykonawczego, typy nieskrócone są traktowane jako dane rzeczywiste.

Sądzę, że wewnętrznie, gdyby bool musiał zostać spakowany do skrzynki, System.Objectponieważ (z powodu skasowania typu lub w przypadku braku możliwości optymalizacji), skończyłoby się to czymś podobnym do tego, trueco odpowiada tej wartości 1.

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

Tak więc, gdy są na wysokim poziomie booli System.Booleanwydają się być identyczne i mogą być podobnie zoptymalizowane, w tym konkretnym przypadku w środowisku wykonawczym, różnice między wersjami pudełkową i nieopakowaną boolsą bezpośrednio widoczne. Podobnie, boolnie można porównywać rozpakowanego z System.Objectktórym jest z natury typem pudełkowym. Ta odpowiedź dotycząca potrzeby boksowania / rozpakowywania idzie głębiej w wyjaśnianie samej zasady.

W językach zarządzanych implementacje środowiska wykonawczego muszą być generalnie zwolnione z pewnych reguł, jeśli chodzi o niektóre podstawowe funkcje środowiska wykonawczego, z pewnością dotyczy to Javy i innych języków opartych na JVM. Chociaż nie znam również CLR, sądzę, że ta sama zasada obowiązuje tutaj.

Podczas gdy to pytanie o „bool” jest aliasem typu dla „System.Boolean” zasadniczo obejmuje ogólne przypadki użycia, podczas zbliżania się do implementacji środowiska wykonawczego dialekt języka C # przypomina bardziej „implementację specyficzną dla języka C #”, co może nieco zginać reguły .

Kristina Brooks
źródło
Poparłem to za twój wgląd - ale nie mogę zaznaczyć tego jako zaakceptowanej odpowiedzi, ponieważ nie jest to wiarygodne, przepraszam :(
Dai