J'étais en cours d'initialisation d'objet et d'initialisation de constructeur pour mon objet, mais je n'ai pas pu obtenir de réponse exacte à ma question. Quelle est la différence entre Case1 et Case2 ici;
Cas 1:
class Program { static void Main(string[] args) { Console.WriteLine("Press any key to stop"); MyBuilder builder = new MyBuilder(); builder.ProcessRecord(2); } }
Cas II: p>
namespace ConsoleApplication2 { class MyBuilder { private MySynchronizer m_synchronizer; public MyBuilder() { m_synchronizer = new MySynchronizer(); } public void ProcessRecord(int recordNumber) { m_synchronizer.Process(recordNumber); } } }
Ceci est un exemple de code pour montrer comment j'appelle ma classe Builder;
namespace ConsoleApplication2 { class MyBuilder { private MySynchronizer m_synchronizer = new MySynchronizer(); public MyBuilder() { } public void ProcessRecord(int recordNumber) { m_synchronizer.Process(recordNumber); } } }
[Désolé, si je ne pouvais pas avoir reformulez correctement la question, auquel cas n'importe qui peut fournir le lien vers un autre article SO]
3 Réponses :
La différence ici est vraiment subtile, et ne peut être facilement appréciée qu’en IL:
// Methods .method public hidebysig specialname rtspecialname instance void .ctor () cil managed { // Method begins at RVA 0x2063 // Code size 18 (0x12) .maxstack 8 IL_0000: ldarg.0 IL_0001: call instance void [mscorlib]System.Object::.ctor() IL_0006: ldarg.0 IL_0007: newobj instance void MySynchronizer::.ctor() IL_000c: stfld class MySynchronizer MyBuilder2::m_synchronizer IL_0011: ret } // end of method MyBuilder2::.ctor
nous donne le constructeur:
class MyBuilder2 { private MySynchronizer m_synchronizer; public MyBuilder2() { m_synchronizer = new MySynchronizer(); } }
où-comme ceci:
.method public hidebysig specialname rtspecialname instance void .ctor () cil managed { // Method begins at RVA 0x2050 // Code size 18 (0x12) .maxstack 8 IL_0000: ldarg.0 IL_0001: newobj instance void MySynchronizer::.ctor() IL_0006: stfld class MySynchronizer MyBuilder1::m_synchronizer IL_000b: ldarg.0 IL_000c: call instance void [mscorlib]System.Object::.ctor() IL_0011: ret } // end of method MyBuilder1::.ctor
nous donne:
class MyBuilder1 { private MySynchronizer m_synchronizer = new MySynchronizer(); public MyBuilder1() { } }
La différence est simplement d'ordre:
MyBuilder1
) se produisent avant l'appel du constructeur de type de base ( objet
est la base ici; call instance void [mscorlib] System.Object ::. ctor ()
est l'appel du constructeur de base) Dans la plupart des cas, cela n'a pas d'importance . À moins que votre constructeur de base n'invoque une méthode virtuelle que le type dérivé remplace: le fait que le champ ait ou non une valeur dans la méthode remplacée sera différent entre les deux.
Comment quelqu'un pourrait-il voir l'IL comme vous l'avez publié?
@Cory J'utilise sharplab comme banc d'essai pour les petites pièces; pour les gros morceaux: réflecteur - mais: essayer ce lien
@Cory en fait, l'une des fonctionnalités les plus utiles pour moi est d'avoir la sortie en C # - ce qui peut sembler étrange, mais vous pouvez l'utiliser pour voir comment le compilateur interprète des concepts complexes tels que les itérateurs, les lambdas, etc.
oui, j'ai vu une tonne de messages montrant comment des choses comme async / await sont traitées par le compilateur ... cet outil sera génial pour le montrer.
Oui @MarcGravell La différence est observée dans l'ordre du constructeur comme expliqué par vous dans le code IL. Merci mec pour une explication approfondie.
Je choisis presque toujours la deuxième option (initialisation à l'intérieur du constructeur). À mon avis, cela rend votre code plus lisible et la logique de contrôle est à l'intérieur du constructeur, ce qui donne plus de flexibilité pour ajouter de la logique à l'avenir.
Mais encore une fois, ce n'est que mon opinion personnelle.
Comme @Marc l'a déjà mentionné, la différence est dans l'ordre du constructeur de base.
J'ai ajouté le constructeur de base
class MyBuilder : Base { }
et modifié ma classe "MyBuilder" pour en dériver comme;
class Base { public Base() { Console.WriteLine("Inside Base constructor"); } }
Maintenant, la sortie de case1 ressemble à:
alors que dans le cas 2:
Par conséquent ,
"pratiquement rien" ... sauf peut-être l'ordre avec les constructeurs de base. Voyez-vous une différence quelque part?
Si vous initialisez une variable membre lorsqu'elle est déclarée (plutôt que de le faire dans un constructeur), ce code d'initialisation précède le corps de tout constructeur que vous pourriez avoir. Mettez un point d'arrêt sur le code d'initialisation, et sur la première instruction de votre constructeur (ajoutez un deuxième constructeur si vous voulez voir comment cela fonctionne) et déboguez votre code. C'est surtout une question de goût, mais c'est particulièrement pratique si votre classe a plusieurs constructeurs
La plus grande différence est quand cela est fait. Lorsque vous mettez quelque chose dans un constructeur, vous savez qu'il sera "toujours" fait. Mettre quelque chose dans une méthode signifie que vous devez appeler la méthode et, à l'avenir, quelqu'un change le code, cela pourrait ne pas être fait ou fait après que cela soit nécessaire.
@ Flydog57 D'accord. C'est pratique si vous avez plusieurs constructeurs et moins sujet aux erreurs, comme dans cas2, quelqu'un pourrait facilement ajouter un autre constructeur et oublier de l'enchaîner.