85 votes

Que fait le drapeau beforefieldinit ?

Que fait le drapeau beforefieldinit ? Lorsque je regarde dans l'IL de ma classe, je vois ce drapeau mais je ne sais pas ce qu'il fait réellement ?

137voto

Jon Skeet Points 692016

Ver mon article sur cette même question.

En gros, beforefieldinit signifie "le type peut être initialisé à tout moment avant que les champs statiques ne soient référencés". En théorie cela signifie qu'il peut être très paresseusement initialisé - si vous appelez une méthode statique qui ne touche aucun champ, le JIT n'a pas besoin d'initialiser le type.

En pratique cela signifie que la classe est initialisée plus tôt qu'il ne le serait autrement - il est acceptable qu'il soit initialisé au début de la première méthode qui pourrait l'utiliser. Comparez cela aux types qui Ne le fais pas. ont beforefieldinit qui leur est appliquée, où l'initialisation du type doit se produire immédiatement avant le premier élément de l'image. réel utiliser.

Donc, supposons que nous avons :

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

Si les deux types ont beforefieldinit (ce qui est le cas par défaut en C#, à moins que le type ne dispose d'un constructeur statique). ambos être initialisé au début de la DoSomething (généralement - ce n'est pas garanti). S'ils n'ont pas beforefieldinit alors seulement un d'entre eux seront initialisés, en fonction de l'indicateur.

C'est pourquoi il est fréquent d'utiliser un constructeur statique (même vide !) lorsque mise en œuvre du modèle singleton .

0 votes

"le type peut être initialisé à tout moment avant que les champs ne soient référencés." Est-ce également le cas pour l'exécution de méthodes statiques ?

0 votes

@RoyiNamir, la spécification CLI dit que si le BeforeFieldInit est appliqué, alors "la méthode d'initialisation du type est exécutée au moment, ou quelque temps avant, le premier accès à tout champ statique défini pour ce type". Si cet attribut est missed(static .ctor), alors "le premier accès à tout champ statique ou d'instance de ce type, ou la première invocation de toute méthode statique, d'instance ou virtuelle de ce type". Donc ce n'est pas vrai pour BeforeFieldInit appliqué à moins que la méthode statique fasse référence à un autre champ statique.

4 votes

J'ai découvert que l'utilisation de constructeurs statiques (c'est-à-dire de classes qui n'ont pas l'indicateur beforefieldinit) est pénalisante pour les performances. Si vous appelez fréquemment les membres statiques d'une certaine classe, il semble que le runtime doive effectuer une vérification supplémentaire avant chaque appel, pour tester si le type a déjà été initialisé ; beforefieldinit évite ces vérifications. Quelques benchmarks étaient environ 50% plus rapides avec beforefieldinit : codeproject.com/Articles/87991/

6voto

OmariO Points 183

On dirait que cela va changer dans la 4.6.

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

0 votes

Génial, cela signifie-t-il qu'il attendra jusqu'au tout dernier moment pour initialiser le champ (indépendamment du fait qu'il ait ou non le statut beforefieldinit ou pas) ?

1 votes

Avant la première utilisation, tous les accès seront précédés d'un contrôle d'initialisation. Après cela, lorsque d'autres méthodes seront utilisées, le code généré accédera directement au champ. S'il s'agit d'un type primitif, il peut même être utilisé comme une constante de temps JIT.

2 votes

Analyse détaillée de Jon sur les changements apportés à l'initialisation des types à partir de .Net 4.0 aquí .

0voto

Eldar Mahmudov Points 21

Lorsqu'un type déclare un constructeur statique explicite, le compilateur juste-à-temps (JIT) ajoute une vérification à chaque méthode statique et constructeur d'instance du type pour s'assurer que le constructeur statique a été appelé précédemment. L'initialisation statique est déclenchée lorsqu'on accède à un membre statique ou lorsqu'une instance du type est créée. Cependant, l'initialisation statique n'est pas déclenchée si vous déclarez une variable du type mais ne l'utilisez pas, ce qui peut être important si l'initialisation change l'état global.

Lorsque toutes les données statiques sont initialisées en ligne et qu'un constructeur statique explicite n'est pas déclaré, les compilateurs du langage intermédiaire de Microsoft (MSIL) ajoutent l'attribut beforefieldinit et un constructeur statique implicite, qui initialise les données statiques, à la définition de type MSIL.

Lorsque le compilateur JIT rencontre l'indicateur beforefieldinit, la plupart du temps, les vérifications des constructeurs statiques ne sont pas ajoutées. L'initialisation statique est garantie à un moment donné avant l'accès à tout champ statique, mais pas avant l'appel d'une méthode statique ou d'un constructeur d'instance. Notez que l'initialisation statique peut se produire à tout moment après la déclaration d'une variable de ce type.

Les vérifications statiques des constructeurs peuvent diminuer les performances. Souvent, un constructeur statique n'est utilisé que pour initialiser des champs statiques, auquel cas vous devez seulement vous assurer que l'initialisation statique a lieu avant le premier accès d'un champ statique. Le comportement beforefieldinit est approprié pour ces types et la plupart des autres types. Il n'est inapproprié que lorsque l'initialisation statique affecte l'état global et que l'une des situations suivantes est vraie :

L'effet sur l'état global est coûteux et n'est pas nécessaire si le type n'est pas utilisé.

On peut accéder aux effets d'état globaux sans accéder aux champs statiques du type.

Pour plus d'informations https://docs.microsoft.com/en-us/dotnet/fundamentals/code-analysis/quality-rules/ca1810

0voto

Ketan Pandhare Points 1

S'il est marqué BeforeFieldInit, la méthode d'initialisation du type est exécutée lors du premier accès à un champ statique défini pour ce type, ou quelque temps avant.

S'il n'est pas marqué BeforeFieldInit, la méthode d'initialisation de ce type est exécutée lors du le premier accès à un champ statique ou d'instance de ce type, ou la première invocation d'une méthode statique, d'instance ou virtuelle de ce type.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X