Wie vermeidet mscorlibs "System.Boolean" Strukturlayoutzyklen?

10

Der Sourcecode für System.Booleanan der Referenzstelle Website heißt es, dass die Instanzen die struct Booleanenthalten nur ein einziges boolFeld: 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;
}

Aber mir ist aufgefallen, dass ...

  • boolist ein C # -Sprachenalias für System.Boolean.
  • Der Typ ist struct Booleanein Werttyp, was bedeutet, dass er sich nicht als Feld enthalten kann .
  • ... aber dieser Code wird vermutlich kompiliert.
  • Ich verstehe, dass Sie, wenn die -nostdlibCompiler-Option festgelegt ist, Ihre eigenen wesentlichen Typdefinitionen wie ,, - angeben System.Stringmüssen System.Int32, System.Exceptiondas ist der einzige Unterschied.
  • Der veröffentlichte Quellcode enthält keine weiteren speziellen Attribute wie [MethodImpl( MethodImplOptions.InternalCall )].

Wie wird dieser Code kompiliert?

Dai
quelle
1
Es ist eine anständige Demonstration, dass die übliche Annahme "es ist ein Alias" ein gebrochenes mentales Modell ist. boolist ein Schlüsselwort in der C # -Sprache. Sowohl der Compiler als auch die Laufzeit verfügen über umfangreiche Kenntnisse über den Typ und benötigen keine Hilfe von System.Boolean. Die Deklarationen in mscorlib für die primitiven Werttypen stimmen mit der Boxdarstellung des Typs überein.
Hans Passant

Antworten:

3

Kurze Antwort : Es ist ein Sonderfall, der sich auf das Typboxen und die zugrunde liegende Darstellung bezieht. Diese Typen sind dem Compiler bekannt und werden daher von den Kernteilen der Laufzeit und dem Compiler / JIT-Optimierer im Vergleich zu regulären Typen geringfügig anders behandelt.


Da dies tief in der Laufzeitimplementierung vergraben ist, würde ich davon ausgehen, dass die Sprachspezifikation nicht auf bestimmte Details der Laufzeitimplementierung eingehen würde. Ich bin mir nicht sicher, ob dies eine ausreichend zufriedenstellende Antwort ist, aber ich denke, in diesem speziellen Fall boolbleibt der Typ unboxed und existiert daher als Rohwerttyp als Teil der Struktur.

Die Semantik des Boxens und Entpackens von Werttypen ist absichtlich undurchsichtig, um die Verwendung der Sprache zu vereinfachen. In diesem Fall Booleanscheint sich die Struktur selbst auf implementierungsspezifische Boxregeln zu stützen, um die tatsächliche Semantik zu implementieren, wie z.

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

Ich glaube an das Obige, eine Box-Struktur, die einen booleschen Typ darstellt, wird zuerst typgeprüft, dann wird sie entpackt und der interne boolWert wird direkt verglichen. Im Gegensatz zu einem Boxed-Typ, bei dem es sich möglicherweise um einen markierten Zeiger oder eine tatsächliche Struktur mit einigen Laufzeittypinformationen handelt, werden Unboxed-Typen als tatsächliche Daten behandelt.

Ich glaube intern, wenn ein Bool verpackt werden System.Objectmüsste, um als (aufgrund von Typlöschung oder wo keine Optimierung möglich wäre) weitergegeben zu werden, würden Sie etwas in dieser Richtung erhalten, für truedas der Wert verpackt wird 1.

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

Während dies auf einem hohen Niveau liegt boolund System.Booleanidentisch zu sein scheint und in ähnlicher Weise optimiert werden kann, werden in diesem speziellen Fall innerhalb der Laufzeit die Unterschiede zwischen der Box- und der Unbox-Version von booldirekt angezeigt . Ähnlich kann ein Unboxed boolnicht mit System.Objecteinem Boxed-Typ verglichen werden . Diese Antwort bezüglich der Notwendigkeit des Boxens / Entpackens geht viel tiefer, um das Prinzip selbst zu erklären.

In verwalteten Sprachen müssen Laufzeitimplementierungen im Allgemeinen von bestimmten Regeln ausgenommen werden, wenn es um einige Kernlaufzeitfunktionen geht. Dies gilt sicherlich für Java und andere JVM-basierte Sprachen. Obwohl ich mit CLR nicht vertraut bin, würde ich denken, dass hier das gleiche Prinzip angewendet wird.

Während diese Frage, ob 'bool' ein Typalias für 'System.Boolean' ist, im Wesentlichen allgemeine Anwendungsfälle abdeckt , ähnelt der Dialekt von C # bei Annäherung an die Laufzeitimplementierung eher dem "implementierungsspezifischen C #", wodurch die Regeln leicht gebogen werden können .

Kristina Brooks
quelle
Ich habe dies für Ihre Einsicht positiv bewertet - aber ich kann dies nicht als akzeptierte Antwort markieren, da es nicht maßgeblich ist, sorry :(
Dai