7
votes

Conversion aveuglément des structures en classes pour masquer le constructeur par défaut?

J'ai lu toutes les questions relatives à ce sujet et ils donnent tous des raisons pour lesquelles un constructeur par défaut sur un struct n'est pas disponible en C #, mais je n'ai trouvé personne qui suggère un cours général d'action lorsqu'elle est confrontée à cette situation.

La solution évidente consiste simplement à convertir simplement le struct à une classe et gérer les conséquences.

Y a-t-il d'autres options pour le garder en tant que struct ?

J'ai couru dans cette situation avec l'un de nos objets d'API de commerce internes. Le concepteur le convertit à partir d'un classe à un struct , et maintenant le constructeur par défaut (qui était privé avant) laisse l'objet dans un état invalide.

Je pensais que si nous allons garder l'objet comme un struct , un mécanisme de vérification de la validité de l'état doit être introduit (quelque chose comme un isvalid propriété). J'ai été rencontré avec 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 levé mes sourcils. (Remarque: L'objet en question est construit «correctement» via des méthodes d'usine statiques, et tous les autres constructeurs sont internes .)

Est-ce que tout le monde convertit simplement leur struct s sur classe es dans cette situation sans une seconde pensée?

Edit: J'aimerais voir quelques suggestions sur la manière de conserver ce type d'objet sous forme de struct - L'objet en question ci-dessus est beaucoup mieux adapté à un struct que comme une classe .


2 commentaires

c'est une excellente question. Vous pouvez concevoir une structure de telle sorte que l'état à zéro est valide, mais cela seul ne fera pas toujours pour une API utilisable. Si le constructeur par défaut est présent, certaines personnes l'appellent inévitablement car elles apparaîtront dans leur IDE et fourniront le chemin du moindre résistance. Et cela conduira à des problèmes que le compilateur devrait attraper, ou ils perdront du temps à essayer de définir des propriétés sur une structure à zéro immuable. Je souhaite que c # vous a permis de masquer le constructeur par défaut et des personnes forcées d'appeler par défaut (...) si elles veulent vraiment une structure à zéro.


En réalité, recherchez cela plus, je pense que la question de la convivialité est vraiment d'intellensense plutôt que du compilateur. Il semble que, une fois une fois, Visual Studio n'a pas montré le constructeur par défaut d'IntelliSense, qui, à mon avis, est la chose sensible à faire. Mais les gens se sont plaints voir ici et à certains Point Il a dû être modifié, car maintenant Visual Studio 2010 apparaît le constructeur vide comme première option.


3 Réponses :


1
votes

La raison en est qu'une structure (une instance de système.valueType) est traitée spécialement par le CLR: il est initialisé avec tous les champs étant 0 (ou par défaut). Vous n'avez même pas vraiment besoin de créer un - juste le déclarer. C'est pourquoi les constructeurs par défaillants sont requis.

Vous pouvez contourner cela de deux manières:

  1. Créez une propriété comme ISVALID pour indiquer s'il s'agit d'une structure valide, comme si vous indiquez et
  2. in .NET 2.0 envisagez d'utiliser NULLABLABLE pour permettre une structure non initialisée (null).

    Modification de la structure à une classe peut avoir des conséquences très subtiles (en termes d'utilisation de la mémoire et d'identité d'objet qui mènent davantage dans un environnement multithread), et non si subtile mais difficile à déboguer NullReferenceExceptions pour des objets non initialisés. < / p>


0 commentaires

4
votes

pour un struct , vous concevez le type de l'instance construite par défaut (champs tout zéro) est un état valide. Vous ne devez pas ] utiliser arbitrairement utiliser struct au lieu de Classe sans bonne raison - il n'y a rien de mal à utiliser un type de référence immuable.

Mes suggestions:

  • Assurez-vous que la raison de l'utilisation d'un struct est valide (un profileur [réel] a révélé des problèmes de performances significatifs résultant d'une lourde attribution d'un objet très léger).
  • concevez le type de sorte que l'instance construite par défaut est valide.
  • Si la conception du type est dictée par des contraintes Interop Native / COM, enveloppez la fonctionnalité et n'exposez pas le struct en dehors de l'emballage (type imbriqué privé). De cette façon, vous pouvez facilement documenter et vérifier l'utilisation correcte des exigences de type contraint.

1 commentaires

Bonne réponse. Un peu, pour mon cas particulier ci-dessus, aucun de ce que vous avez dit ne s'applique, car des problèmes sont plus facilement introduits dans le code lorsque l'objet est un type de référence ... Par conséquent, pourquoi il a été converti en structure. Mais dans de nombreux autres cas, l'utilisation d'un type de référence immuable serait une solution viable.



0
votes

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

Vous avez 3 options ici

  1. appeler le constructeur par défaut 1000 fois, ou
  2. Création de données corrompues (notez qu'une struct peut contenir des références; si vous n'initialisez pas ou n'implique pas la référence, vous pouvez potentiellement accéder à la mémoire arbitraire), ou
  3. vierge 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 bloqués avec des zéros. Cela obtient également un comportement plus cohérent entre les structs et les classes et aucun code dangereux. Il permet également à la framework .NET de ne pas spécialiser quelque chose comme nouvel octet [1000] .

    et c'est le constructeur par défaut pour les exigences de Structs .NET et prend soin de lui-même: zéro. Tous les octets.

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

    • Ajoutez une propriété AM-I-initialisée à la structure (comme hasvalue sur nullable ).
    • Autoriser la structure à zéro d'être une valeur valide (comme 0 est une valeur valide pour une décimale).

0 commentaires