Nouvel opérateur en C # vs C ++

Venant de C ++, je suis confus quant à l’utilisation du new mot-clé en C #.

Je comprends que cela ne fonctionne pas comme le nouveau C ++, dans la mesure où vous n’avez pas à contrôler manuellement la durée de vie de l’object, car C # a un garbage collection.

Cependant, lors de la lecture de code C # sur d’autres peuples, je remarque des déclarations comme dans l’extrait de code 1. Ne serait-il pas beaucoup plus facile d’éviter l’utilisation de new , comme dans l’extrait de code 2?

Extrait 1

 Foo fooInstance = new Foo(); 

Extrait 2

 Foo fooInstance; 

Ma question est la suivante: quelles sont les différences entre snippet 1 et snippet 2 et pourquoi devrais-je en préférer un?

Nous devons distinguer trois cas: (1) les variables locales, (2) les champs (non statiques) dans les structures et (3) les champs dans les classes.


Pour les variables locales, c’est-à-dire des variables déclarées dans une méthode (ou dans un constructeur, ou un accesseur propriété / indexeur / événement), les deux ne sont pas équivalents:

 class C { void M() { Foo fooInstance = new Foo(); // the variable is "definitely assigned" and can be read (copied, passed etc) // consider using the 'var' keyword above! } } class C { void M() { Foo fooInstance; // the variable is not "definitely assigned", you cannot acquire its value // it needs to be assigned later (or can be used as 'out' parameter) } } 

Pour les champs d’instance (champs non statiques) à l’intérieur d’une struct , un seul des “extraits” est autorisé:

 struct S { Foo fooInstance = new Foo(); // comstack-time error! cannot initialize here } struct S { Foo fooInstance; // OK, access level is 'private' when nothing is specified } 

Pour les champs d’une classe (et static champs static d’une structure), la situation varie selon que Foo est lui-même un type de référence ( class ) ou un type de valeur ( struct ou enum ). La valeur default(Foo) défaut default(Foo) d’un type de référence est null , la référence qui ne fait référence à rien. La valeur default(Foo) défaut default(Foo) ou un type de valeur est “l’instance” du type où tous les champs ont leurs valeurs par défaut. Pour les types de valeur (struct et enum), new Foo() (sans argument) et default(Foo) est la même chose. Donc:

 class C { Foo fooInstance = new Foo(); // OK, private } class C { Foo fooInstance; // OK, private // equivalent to 'Foo fooInstance = null;' if 'Foo' is a reference type (class, interface, delegate, array) // equivalent to 'Foo fooInstance = new Foo();' is 'Foo' is a value type (struct, enum) } 

Il convient de noter que si Foo est un type de référence, l’expression new Foo() n’est autorisée que si le type a réellement un constructeur qui prend 0 argument, et si ce constructeur est accessible.

Dans (1), nous avons ignoré le cas idiot où Foo est une structure sans champs d’instance.

En supposant que Foo soit un type de référence semblable à une classe, le deuxième fragment de code n’atsortingbue qu’un pointeur. Le code C ++ équivalent serait

 Foo* fooInstance; 

Vos extraits 1 et 2 ne sont tout simplement pas équivalents.

La seconde crée un object de type Foo pointe sur null dans memeroy. Le premier pointe sur le nouvel object à l’aide du constructeur par défaut.

Si vous utilisez le second et dites fooInstance.SomeProperty = quelque chose. Cela lève une exception lorsque fooInstance pointe sur null.

Si tu utilises

 Foo fooInstance; 

… en C #, vous créez simplement une variable de référence sur une stack qui ne pointe vers rien; aucun constructeur par défaut n’est appelé (comme ce serait le cas en C ++).

Le fragment 2 déclare simplement la référence. Vous n’avez pas encore instancié l’object. Si vous tentiez d’accéder à la référence dans Snippet 2, vous obtiendrez une erreur du compilateur indiquant que la valeur n’a pas été initialisée. Cela diffère de C ++ où Snippet 2 déclarerait un object construit sur la stack.

Le premier extrait

 Foo fooInstance = new Foo(); 

comme cela a été dit, créera une nouvelle instance de Foo et y placera une référence dans la variable fooInstance .

Pour le deuxième extrait

  Foo fooInstance; 

cela dépend de l’endroit où il est placé:

  public class MyClass { Foo m_foo = null; // member, the "= null" part is redundant and not needed Foo m_foo = new Foo(); // member, initialized as part of the constructor call void Bar() { Foo f; // Local variable f.MyMethod(); // Comstack time error: f is not initialized Foo f2=null; f2.MyMethod(); // Runtime error: Nullreference exception } } 

Une prudence supplémentaire doit être prise si Foo n’est pas déclaré en tant que classe mais en tant que struct. Bien qu’elle soit également initialisée à l’aide de new , l’instance est alors créée sur la stack.