Ok pour nous pas d'instance, mais est ce que au niveau de l'IL une instance est réellement crée ?
****************************************
- I don’t write plumbing code anymore
- I use PostSharp
- And you?
****************************************
+1
Oui ça existe toujours en VB.NET. .... Malheureusement.
Pas d'instance à ma connaissance.
On peut agir manuellement sur le code pour dire qu'une méthode est inline ou pas? (Comme en C++). Si oui comment?
Sinon quelles sont les autres critères qui peuvent rendre une méthode de classe inline?
Je pensais que seul les propriétés étaient inline en .NET
Salut,
en IL non plus, il n'y a pas d'instance. De plus, il existe des instruction specifique pour les membres statiques. Un exemple 'bateau' pour comparer :
Donc en gros deux classes faisant la meme chose, la premiere statiquement, l'autre etant un objet. En IL, le Main nous donnera ceci :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43 using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace ConsoleApplication1 { class Program { static void Main(string[] args) { string str = "Salut !"; StaticClass.Display(str); new InstanceClass().Display(str); } } public static class StaticClass { static string str; public static void Display(string s) { str = s; Console.WriteLine(str); } } public class InstanceClass { string str; public void Display(string s) { str = s; Console.WriteLine(str); } } }
On voit bien que dans le cas static, il n'y aucune creation d'instance, et que l'on appelle directement la methode Display. Dans le second, il y a d'abord un newobj puis l'appel concret. Dans le corps du Display Static, on trouve :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 .method private hidebysig static void Main(string[] args) cil managed { .entrypoint .maxstack 2 .locals init ( [0] string str) L_0000: nop L_0001: ldstr "Salut !" L_0006: stloc.0 L_0007: ldloc.0 L_0008: call void ConsoleApplication1.StaticClass::Display(string) L_000d: nop L_000e: newobj instance void ConsoleApplication1.InstanceClass::.ctor() L_0013: ldloc.0 L_0014: call instance void ConsoleApplication1.InstanceClass::Display(string) L_0019: nop L_001a: ret }
En fait, les instructions stsfld et ldsfld sont des instructions specialisées dans la manipulation des champs statiques. Donc ici, on enregistre le premier argument dans le champs static str (ldarg.0 et stsfld) puis on passe le champ static sur le stack (ldsfld) et on l'affiche par un CW (call ...).
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11 .method public hidebysig static void Display(string s) cil managed { .maxstack 8 L_0000: nop L_0001: ldarg.0 L_0002: stsfld string ConsoleApplication1.StaticClass::str L_0007: ldsfld string ConsoleApplication1.StaticClass::str L_000c: call void [mscorlib]System.Console::WriteLine(string) L_0011: nop L_0012: ret }
Pour la methode d'instance :
c'est la meme idée (les deux methodes faisant la meme chose), mais il faut jouer avec une reference supplementaire, le pointeur vers this (qui est en fait le premier argument de la methode dans les objets, ce qui explique que le premier argument d'une methode d'instance est à l'index 1 et non 0 comme precedemment). En effet les instructions stfld et ldfld attendent deux choses sur le stack, la reference vers l'objet en question (this ici) et la nouvelle valeur (pour stfld du moins).
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13 .method public hidebysig instance void Display(string s) cil managed { .maxstack 8 L_0000: nop L_0001: ldarg.0 L_0002: ldarg.1 L_0003: stfld string ConsoleApplication1.InstanceClass::str L_0008: ldarg.0 L_0009: ldfld string ConsoleApplication1.InstanceClass::str L_000e: call void [mscorlib]System.Console::WriteLine(string) L_0013: nop L_0014: ret }
Enfin pour la structure des classes en langage IL, une classe static est presenté comme suit :
la classe, pour nous static, est pour le compilateur abstract et sealed (ce qui est impossible à specifier pour une classe => erreur compilateur), et de plus, le compilateur ne generera pas de constructeur par defaut, ce qu'il a fait pour la classe d'instance ci-dessus.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2 .class public abstract auto ansi sealed beforefieldinit StaticClass extends [mscorlib]System.Object
En conclusion, meme en IL, avec une classe static, tu es sur qu'aucune instance de ce type ne sera jamais créé, ou utilisée en classe de base (pas de .ctor, sealed, abstract)
Pour revenir au sujet du thread, les classes statics, je les utilise pour definir des constantes, ou pour "enfermer" des methodes p/invokées (ce que fait Microsoft dans son framework d'ailleurs pour tout les appels de ce type). Mais le probleme des classes statics, c'est que tu ne peux pas facilement controler la durée de vie de ses membres contrairement à une instance qui peut implementer IDisposable, donc j'evite de tenir des ressources qui pourrait etre amené à etre disposées ou qui auraient une durée de vie plus courte que le programme, dans des elements statics.
Edit ; @ Abelman
Apparement, on ne peut pas jouer par instructions pour forcer un inlining en C#, mais Microsoft donne quand meme une liste pour savoir si une methode sera inlinée :
NB : ca date de 2003, donc peut etre est-ce different maintenant.Methods that are greater than 32 bytes of IL will not be inlined.
Virtual functions are not inlined.
Methods that have complex flow control will not be in-lined. Complex flow control is any flow control other than if/then/else; in this case, switch or while.
Methods that contain exception-handling blocks are not inlined, though methods that throw exceptions are still candidates for inlining.
If any of the method's formal arguments are structs, the method will not be inlined.
Moi un truc m'embête lorsque vous dites pas d'instance. Cela voudrait dire que les valeurs des variables de la classe static ne sont pas stockées en mémoire mais dans un fichier binaire et qu'on le lirait lorsque l'on veut récupérer une de ces valeurs ?
Dans ce cas la le code serait stockées dedans également, puis au moment de l'utilisation d'une méthode, il serait lu, compilé, puis interprété ?
Pourquoi faire compliqué lorsque l'on peut faire encore plus compliqué.
Je ne pense pas que l'on puisse agir directement sur l'inlining...Le compilateur utilise une heuristique un peu complexe pour choisir les méthodes candidate à "l'inlining".
Ce que je sais :
- Les méthodes dont l'IL fait plus de 32 bytes ne sont pas candidates.
- Les méthodes virtuelles ne sont pas candidates.
- Les méthodes avec un contrôle de flux complexe ne sont pas candidates.
- Les méthodes comportant un block de gestion d'exception ne sont pas candidates. (mais les méthodes pouvant lever une exception peuvent l'être).
- Les méthodes ayant un struct comme paramètre ne sont pas candidates.
Donc non, il n'y a pas que les propriétés qui sont "inlinées", mais elles sont effectivement des candidates privilègiées.
Certains critères qui excluent "l'inlining" peuvent paraître limites, et on se dit que ça ne laisse pas beaucoup de candidats, mais il ne faut pas oublier que l'on parle d'un compilateur JIT et qu'il faut bien trouver un compromis entre sa vitesse d'exécution et les optimisation qu'il peut faire...
Précision : j'avais cherché ces informations il y a un bon moment déjà, et du coup je certifie leur pertinence sur le fx 1.1, mais il est possible que les choses aient un peu changé sur le 2.0 et le 3.0 !
In my experience, any attempt to make any system idiot proof will only challenge God to make a better idiot.
Euh... perso moi je vois rien du tout ! Mais merci pour ce petit cours de MSIL, ça me rappelle le bon vieux temps de l'assembleur...On voit bien que dans le cas static, il n'y aucune creation d'instance
Oula, pas du tout... les valeurs sont bien stockées en mémoire, et n'ont d'existence qu'au cours de l'éxécution du programme. D'ailleurs la portée des membres statiques d'une classe est limitée à l'application : si tu lances 2 programmes qui appellent tous les 2 Process.GetCurrentProcess() (par exemple), le résultat ne sera pas le même, heureusement !Moi un truc m'embête lorsque vous dites pas d'instance. Cela voudrait dire que les valeurs des variables de la classe static ne sont pas stockées en mémoire mais dans un fichier binaire et qu'on le lirait lorsque l'on veut récupérer une de ces valeurs ?
Dans ce cas la le code serait stockées dedans également, puis au moment de l'utilisation d'une méthode, il serait lu, compilé, puis interprété ?
Pas de questions techniques par MP ! Le forum est là pour ça...
Tutoriels : Les nouveautés de C# 6 - Accès aux données avec Dapper - Extraction de données de pages web à l'aide de HTML Agility Pack - La sérialisation XML avec .NET (Aller plus loin) - Les markup extensions en WPF
Salut,
c'est juste que le champs, methodes ou autres n'est lié à aucune instance, mais existe dans le type en tant que tel. Comme le dirait le standard du CLI :
Si tu preferes, il existe une initialisation pour tous les types que tu utilises, et independemment de toutes creations d'instance de ce type. Donc les valeurs placées en static, sont stockés dans la representation du type lui-meme et initialisé avant toute utilisation par le cctor. (et par extension est partagé par toutes les instances de ce type).Fields can be marked as static, indicating that the field is not part of values of the type but rather a location associated with the type as a whole. Locations for the static fields are created when the type is loaded and
initialized when the type is initialized.
Fields not marked as static define the representation of a value of a type by defining the substructure of the value (see §8.4.1). Locations for such fields are created within every value of the type whenever a new value is
constructed. They are initialized during construction of the new value. A non-static field of a given name is always located at the same place within every value of the type.
En effet j'essayé d'imaginer où cela pouvait être stocké.Pourquoi stockées dans un fichier?
Elles sont stockées en mémoire à une adresse qui n'est "liée" à aucune instance si je peux me permettre de parler ainsi.
Exactement comme serait stockée une variable globale en C.
Pour moi une instance d'une classe, cela veut dire que l'on a une petite zone mémoire représentant l'objet.
Alors quand j'ai lu : classe static ne possède pas d'instance, j'en ai conclu pas de case mémoire.
Bon assez basique comme résonnement, mais bon si les données sont bien stocké en mémoire, alors c'est comme une sorte d'instance unique pour tout le programme mais que l'on ne peut pas appeller instance .
Je comprends mieux le problème et la comparaison avec le singleton.
Pourquoi faire compliqué lorsque l'on peut faire encore plus compliqué.
Ok je comprends, c'est la différence avec le singleton.Si tu preferes, il existe une initialisation pour tous les types que tu utilises, et independemment de toutes creations d'instance de ce type. Donc les valeurs placées en static, sont stockés dans la representation du type lui-meme et initialisé avant toute utilisation par le cctor. (et par extension est partagé par toutes les instances de ce type).
Bref on met les valeurs dans une case mémoire partagé par tout le monde que cela soit visible de toutes classes comme un type de données.
En même temps je me demande du coup si ce n'est pas plus facile d'accés pour un pirate qui essayerais de pirater ton application, comme les variables globales en C ?
Pourquoi faire compliqué lorsque l'on peut faire encore plus compliqué.
Je me demande où tu as pêché ça... les variables globales sont pas plus faciles à pirater que les autres ! Ce serait même plutot le contraire, du moins dans le cas d'une attaque par buffer overflow.je me demande du coup si ce n'est pas plus facile d'accés pour un pirate qui essayerais de pirater ton application, comme les variables globales en C
Pas de questions techniques par MP ! Le forum est là pour ça...
Tutoriels : Les nouveautés de C# 6 - Accès aux données avec Dapper - Extraction de données de pages web à l'aide de HTML Agility Pack - La sérialisation XML avec .NET (Aller plus loin) - Les markup extensions en WPF
Pourquoi faire compliqué lorsque l'on peut faire encore plus compliqué.
je suis pas non plus spécialiste du hacking...
moi aussi mes profs disaient de pas utiliser de variables globales, mais c'etait plutot parce que ce n'etait pas "propre"...
Pas de questions techniques par MP ! Le forum est là pour ça...
Tutoriels : Les nouveautés de C# 6 - Accès aux données avec Dapper - Extraction de données de pages web à l'aide de HTML Agility Pack - La sérialisation XML avec .NET (Aller plus loin) - Les markup extensions en WPF
Salut,
si tu parles du chargement concret (lire l'assembly) du type, je suppose que cela se produit au lancement de l'application (quand la CLR va lire les metadatas et decouvrir ainsi les types, modules et assemblies). Si tu veux parler de l'initialisation, alors oui, tu es sur que les types statics seront initialisés, avant tout appel à un membre static de la classe, par le cctor. D'ailleurs, il y a certaines differences à noter entre le fait d'initialiser par un constructeur static explicite et d'initialiser les champs statics inline, notamment en ce qui concerne les types instanciables et possedant des champs statics. Plus de precisions sur cet article.
Vous avez un bloqueur de publicités installé.
Le Club Developpez.com n'affiche que des publicités IT, discrètes et non intrusives.
Afin que nous puissions continuer à vous fournir gratuitement du contenu de qualité, merci de nous soutenir en désactivant votre bloqueur de publicités sur Developpez.com.
Partager