C # struct new StructType () vs default (StructType)

Dis que j’ai un struc

public struct Foo { ... } 

Y a-t-il une différence entre

 Foo foo = new Foo(); 

et

 Foo foo = default(Foo); 

?

Vous pourriez vous demander pourquoi, si elles sont exactement les mêmes, il y a deux façons de faire la même chose.

Ils ne sont pas tout à fait les mêmes car chaque type de référence ou type de valeur est garanti par défaut, mais tous les types de référence ne sont pas nécessairement dotés d’un constructeur sans paramètre:

 static T MakeDefault() { return default(T); // legal // return new T(); // illegal } 

Non, les deux expressions donneront le même résultat exact.

Comme les structs ne peuvent pas contenir de constructeurs explicites sans paramètre (c.-à-d. Que vous ne pouvez pas en définir un vous-même), le constructeur par défaut vous donnera une version de la structure avec toutes les valeurs nulles. C’est le même comportement que le default vous donne également.

Pour les types de valeur, les options sont pratiquement équivalentes.

Cependant, j’ai été insortinggué par les recherches empiriques de Jon Skeet sur les «instructions» entraînant l’invocation du constructeur par défaut sans paramètre d’une structure lorsque celui-ci est spécifié dans CIL (vous ne pouvez pas le faire). Entre autres choses, il avait essayé default(T) et new T()T est un paramètre de type. Ils semblaient équivalents; aucun d’eux ne semblait appeler le constructeur.

Mais le seul cas (il semble) qu’il n’avait pas essayé était default(Foo)Foo est un type de structure réel.

J’ai donc pris son code pour la structure «piratée» et l’ai essayé pour moi-même.


Il s’avère que default (Foo) n’appelle pas le constructeur, alors que le nouveau Foo () le fait.

En utilisant un type de structure Oddity qui spécifie un constructeur sans paramètre:

Avec les optimisations désactivées , la méthode:

 private void CallDefault() { Oddity a = default(Oddity); } 

produit le CIL (sans nop s, ret s etc.):

 L_0001: ldloca.sa L_0003: initobj [Oddity]Oddity 

alors que la méthode:

 private void CallNew() { Oddity b = new Oddity(); } 

produit:

 L_0001: ldloca.sb L_0003: call instance void [Oddity]Oddity::.ctor() 

Lorsque les optimisations sont activées , le compilateur semble optimiser la CallDefault totalité de la méthode CallDefault dans une opération sans opération, mais conserve l’appel au constructeur dans CallNew (pour les effets secondaires potentiels?).

La spécification de langue (§4.1.2 et §5.2) est votre ami. Plus précisément:

Pour une variable de type valeur , la valeur par défaut est la même que la valeur calculée par le constructeur par défaut du type valeur (§4.1.2).

(Italique dans l’original.)

Notez que ce n’est pas la même chose pour les types de référence.

Pour une variable de type référence, la valeur par défaut est null .

Ceci est nettement différent de la valeur produite par un constructeur par défaut, s’il en existe un.

default mot-clé default est utile lorsque vous ne connaissez pas le type exact et qu’il fonctionne non seulement pour les structures, par exemple pour les génériques:

 T FirstOrDefault(IEnumerable source) { if (...source is empty...) return default(T); } 

Cela retournera null pour les types de référence, valeur par défaut pour les types primitifs (0 pour les nombres, faux pour bool), structure inialisée par défaut, etc …

Lorsque le type est connu à la compilation, cela n’a aucun sens d’utiliser la default , vous pouvez utiliser le new Foo() place.