2
votes

Différence lors de l'initialisation de l'objet dans le constructeur de la déclaration de classe v / s

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]


4 commentaires

"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.


3 Réponses :


9
votes

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:

    Les
  • initialiseurs de champ ( 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)
  • les constructeurs se produisent après l'appel du constructeur de type 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.


5 commentaires

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.



0
votes

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.


0 commentaires

3
votes

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 à:

entrez la description de l'image ici

alors que dans le cas 2:

 entrez la description de l'image ici

Par conséquent ,

  • Si vous avez plusieurs constructeurs, alors l'approche case1 pourrait être meilleure, car il y a moins d'erreurs car quelqu'un pourrait facilement ajouter un autre constructeur et oublier de l'enchaîner.
  • Si vous avez un seul constructeur et aucun flux logique qui dépend de l'ordre du constructeur de base, alors le cas2 semble meilleur, car cela rendra le code plus propre. [aucune offense, préférence personnelle]


0 commentaires