Was macht beforefieldinit flag?

81

Was macht beforefieldinit flag? Wenn ich in die IL meiner Klasse schaue, sehe ich diese Flagge, aber ich weiß nicht, was diese Flagge tatsächlich tut?

Embedd_Khurja
quelle

Antworten:

131

Siehe meinen Artikel zu diesem Thema.

Grundsätzlich beforefieldinitbedeutet dies , dass "der Typ zu jedem Zeitpunkt initialisiert werden kann, bevor auf statische Felder verwiesen wird". Theoretisch bedeutet dies, dass es sehr träge initialisiert werden kann. Wenn Sie eine statische Methode aufrufen, die keine Felder berührt, muss die JIT den Typ nicht initialisieren.

In der Praxis bedeutet dies, dass die Klasse früher initialisiert wird als sonst - es ist in Ordnung, dass sie zu Beginn der ersten Methode initialisiert wird, die sie möglicherweise verwendet. Vergleichen Sie dies mit Typen, die nicht auf sie beforefieldinitangewendet wurden, wobei die Typinitialisierung unmittelbar vor der ersten tatsächlichen Verwendung erfolgen muss.

Nehmen wir also an, wir haben:

public static void DoSomething(bool which)
{
    if (which)
    {
        FirstType.Foo();
    }
    else
    {
        SecondType.Bar();
    }
}

Wenn beide Typen auf sie beforefieldinitangewendet wurden (was in C # standardmäßig der Fall ist, es sei denn, der Typ verfügt über einen statischen Konstruktor), werden beide zu Beginn der DoSomethingMethode initialisiert (normalerweise - dies ist nicht garantiert). Wenn dies nicht der Fall ist, wird beforefieldinitnur einer von ihnen basierend auf dem Flag initialisiert.

Aus diesem Grund wird bei der Implementierung des Singleton-Musters häufig ein statischer Konstruktor (sogar ein leerer!) Verwendet .

Jon Skeet
quelle
"Der Typ kann zu jedem Zeitpunkt initialisiert werden, bevor auf Felder verwiesen wird." Gilt das auch für statische Methoden?
Royi Namir
@RoyiNamir, die CLI-Spezifikation besagt, dass, wenn BeforeFieldInit angewendet wird, "die Initialisierungsmethode des Typs beim oder irgendwann vor dem ersten Zugriff auf ein für diesen Typ definiertes statisches Feld ausgeführt wird". Wenn dieses Attribut fehlt (statischer .ctor), dann "erster Zugriff auf ein statisches oder Instanzfeld dieses Typs oder erster Aufruf einer statischen, Instanz oder virtuellen Methode dieses Typs". Daher gilt dies nicht für BeforeFieldInit, es sei denn, die statische Methode verweist auf ein anderes statisches Feld.
Arman McHitarian
3
Ich habe festgestellt, dass die Verwendung statischer Konstruktoren (dh Klassen ohne das Flag beforefieldinit) einen Leistungsverlust verursacht. Wenn Sie häufig statische Mitglieder einer bestimmten Klasse aufrufen, muss die Laufzeit vor jedem Aufruf eine zusätzliche Überprüfung durchführen, um zu testen, ob der Typ noch initialisiert wurde. beforefieldinit vermeidet diese Überprüfungen. Einige Benchmarks waren mit beforefieldinit etwa 50% schneller: codeproject.com/Articles/87991/…
Qwertie
6

Sieht so aus, als würde sich das in 4.6 ändern

https://github.com/dotnet/coreclr/issues/1193

OmariO
quelle
Genial, heißt das also, dass es bis zum allerletzten Moment warten wird, um das Feld zu initialisieren (unabhängig davon, ob es vorhanden ist beforefieldinitoder nicht)?
James Ko
1
Vor der ersten Verwendung wird allen Zugriffen eine Initialisierungsprüfung vorangestellt. Wenn danach andere Methoden eingestellt werden, greift der generierte Code direkt auf das Feld zu. Wenn es sich um einen primitiven Typ handelt, kann es sogar als JIT-Zeitkonstante verwendet werden.
OmariO
2
Jons detaillierte Analyse zu Änderungen an der Typinitialisierung ab .NET 4.0 hier .
RBT