Question

J'ai lu toutes les questions liées à ce sujet, et elles expliquent toutes les raisons pour lesquelles un constructeur par défaut sur un struct n'est pas disponible en C #, mais je n'ai encore trouvé personne qui suggère un plan d'action général lorsqu'il est confronté. cette situation.

La solution évidente consiste simplement à convertir le class en un IsValid et à en gérer les conséquences.

Existe-t-il d'autres options pour le conserver en tant que internal?

J'ai rencontré ce problème avec l'un de nos objets API de commerce interne. Le concepteur l'a converti d'un <=> à un <=>, et le constructeur par défaut (qui était auparavant privé) laisse l'objet dans un état non valide.

Je pensais que si nous gardions l'objet en tant que <=>, un mécanisme de contrôle de la validité de l'état devrait être introduit (quelque chose comme une propriété <=>). J'ai rencontré beaucoup de résistance et une explication de & "Quiconque utilise l'API ne doit pas utiliser le constructeur par défaut, &"; un commentaire qui a certainement soulevé mes sourcils. (Remarque: l'objet en question est construit & «Correctement»! À l'aide de méthodes d'usine statiques et tous les autres constructeurs sont <=>.)

Tout le monde convertit-il simplement ses <=> s en <=> es dans cette situation sans y réfléchir à deux fois?

Éditer: je voudrais voir quelques suggestions sur la façon de conserver ce type d’objet en tant que <=> - l’objet en question ci-dessus convient beaucoup mieux comme <=> que comme <=>.

Était-ce utile?

La solution

Pour un struct, vous concevez le type de sorte que l'instance construite par défaut (tous les champs nuls) soit un état valide. Vous ne [ ne devez pas ] utiliser arbitrairement class au lieu de <=> sans bonne raison - l'utilisation d'un type de référence immuable ne présente aucun inconvénient.

Mes suggestions:

  • Assurez-vous que la raison d'utiliser un <=> est valide (un profileur [réel] a révélé d'importants problèmes de performances résultant de l'allocation lourde d'un objet très léger).
  • Définissez le type pour que l'instance construite par défaut soit valide.
  • Si la conception du type est dictée par des contraintes d'interop natif / COM, enveloppez la fonctionnalité et n'exposez pas <=> à l'extérieur du wrapper (type imbriqué privé). De cette façon, vous pouvez facilement documenter et vérifier l'utilisation appropriée des exigences de type contraint.

Autres conseils

La raison en est qu’une structure (une instance de System.ValueType) est traitée spécialement par le CLR: elle est initialisée avec tous les champs valant 0 (ou par défaut). Vous n'avez même pas vraiment besoin d'en créer un - il suffit de le déclarer. C'est pourquoi les constructeurs par défaut sont obligatoires.

Vous pouvez contourner ce problème de deux manières:

  1. Créez une propriété comme IsValid pour indiquer si c'est une structure valide, comme vous l'indiquez et
  2. dans .Net 2.0, envisagez d’utiliser Nullable < T > autoriser une structure non initialisée (null).

La modification de la structure en classe peut avoir des conséquences très subtiles (en termes d'utilisation de la mémoire et d'identité d'objet qui apparaissent davantage dans un environnement multithread), et non subtiles mais difficiles à déboguer pour les objets non initialisés. <

La raison pour laquelle il n'est pas possible de définir un constructeur par défaut est illustrée par l'expression suivante:

new MyStruct[1000];

Vous avez 3 options ici

  1. appelant le constructeur par défaut 1000 fois, ou
  2. créer des données corrompues (notez qu'une structure peut contenir des références; si vous n'initialisez pas ou ne videz pas la référence, vous pourriez potentiellement accéder à de la mémoire arbitraire), ou
  3. vide la mémoire allouée avec des zéros (au niveau des octets).

.NET fait la même chose pour les structures et les classes: les champs et les éléments de tableau sont masqués avec des zéros. Cela donne également un comportement plus cohérent entre les structures et les classes et pas de code non sécurisé. Cela permet également au framework .NET de ne pas spécialiser quelque chose comme new byte[1000].

Et c'est le constructeur par défaut pour structs .NET exige et prend soin de lui-même: mettre à zéro tous les octets.

Maintenant, pour gérer cela, vous avez plusieurs options:

  • Ajoutez une propriété Am-I-Initialized à la structure (comme HasValue sur Nullable).
  • Permettez à la structure mise à zéro d'être une valeur valide (comme 0 est une valeur valide pour un décimal).
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top