Co robi flaga beforefieldinit?

82

Co robi flaga beforefieldinit? Kiedy patrzę na IL mojej klasy, widzę tę flagę, ale nie wiem, co ta flaga właściwie robi?

Embedd_Khurja
źródło

Odpowiedzi:

132

Zobacz mój artykuł na ten temat.

Zasadniczo beforefieldinitoznacza „typ można zainicjować w dowolnym momencie przed odwołaniem się do jakichkolwiek pól statycznych”. W teorii oznacza to, że może być inicjalizowany bardzo leniwie - jeśli wywołasz metodę statyczną, która nie dotyka żadnych pól, JIT nie musi inicjować typu.

W praktyce oznacza to, że klasa jest inicjalizowana wcześniej niż byłoby inaczej - można ją zainicjować na początku pierwszej metody, która może jej użyć. Porównaj to z typami, które nie zostały beforefieldinitdo nich zastosowane, gdzie inicjalizacja typu musi nastąpić bezpośrednio przed pierwszym faktycznym użyciem.

Załóżmy więc, że mamy:

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

Jeśli beforefieldinitzastosowano do nich oba typy (co w C # robią domyślnie, chyba że typ ma konstruktora statycznego), oba zostaną zainicjowane na początku DoSomethingmetody (zwykle - nie jest to gwarantowane). Jeśli nie mają, beforefieldinittylko jeden z nich zostanie zainicjowany na podstawie flagi.

Dlatego często podczas implementowania wzorca singleton używa się konstruktora statycznego (nawet pustego!) .

Jon Skeet
źródło
„typ można zainicjować w dowolnym momencie przed odwołaniem się do jakichkolwiek pól”. czy dotyczy to również uruchamiania metod statycznych?
Royi Namir
@RoyiNamir, specyfikacja CLI mówi, że jeśli zastosowana zostanie metoda BeforeFieldInit, wówczas „metoda inicjalizacji typu jest wykonywana przy lub kiedyś wcześniej, przy pierwszym dostępie do dowolnego pola statycznego zdefiniowanego dla tego typu”. Jeśli ten atrybut zostanie pominięty (static .ctor), wówczas „najpierw uzyskaj dostęp do dowolnego pola statycznego lub instancji tego typu lub pierwsze wywołanie dowolnej metody statycznej, instancji lub metody wirtualnej tego typu”. Więc nie jest to prawdą dla zastosowanego BeforeFieldInit, chyba że metoda statyczna odwołuje się do innego pola statycznego.
Arman
3
Odkryłem, że użycie statycznych konstruktorów (tj. Klas, które nie mają flagi beforefieldinit) wiąże się z obniżeniem wydajności. Jeśli często wywołujesz statyczne elementy członkowskie określonej klasy, wydaje się, że środowisko wykonawcze musi wykonać dodatkowe sprawdzenie przed każdym wywołaniem, aby sprawdzić, czy typ został już zainicjowany; beforefieldinit unika tych kontroli. Kilka testów porównawczych było o 50% szybszych dzięki beforefieldinit: codeproject.com/Articles/87991/…
Qwertie
6

Wygląda na to, że to się zmieni w 4.6

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

OmariO
źródło
Świetnie, czy to oznacza, że ​​zainicjowanie pola będzie czekało do ostatniej chwili (niezależnie od tego, czy tak beforefieldinitbyło)?
James Ko
1
Przed pierwszym użyciem wszystkie dostępy zostaną poprzedzone sprawdzeniem inicjalizacji. Po tym, gdy inne metody zostaną dołączone, wygenerowany kod uzyska bezpośredni dostęp do pola. Jeśli jest typu pierwotnego, można go nawet użyć jako stałej czasowej JIT.
OmariO,
2
Szczegółowa analiza Jona dotycząca zmian w inicjalizacji typu rozpoczynającej .Net 4.0 tutaj .
RBT