Question

J'ai une structure c # où je dois interdire d'appeler le constructeur no args dessus.

MyStruct a;
/// init a by members   // OK
MyStruct b = MyStruct.Fact(args); // OK, inits by memebers

MyStruct s = new MyStruct(); // can't have that

Je le fais principalement pour imposer des valeurs explicet à tous les membres, car il n'y a pas de valeurs par défaut valides et tous les membres doivent avoir des valeurs valides.

En C ++, ce serait facile, ajoutez un constructeur privé, mais c # ne le permet pas.

Existe-t-il un moyen de prévenir ce qui précède?

Je dois vraiment imposer l'utilisation d'une usine afin d'empêcher tous les appels de constructeur publics de fonctionner aussi bien.

Description complète: pour éviter une dépendance mono, l'application c # est automatiquement traduite en D où new Struct () donne lieu à un pointeur et gâche tout pour moi. Cependant, cette question est pertinente malgré cela, alors ignorez-la.

Était-ce utile?

La solution

Vous ne pouvez pas. Toutes les structures ont un constructeur public sans paramètre par définition en C #. (Dans le CLR, pratiquement aucun d'entre eux ne le fait, mais ils peuvent toujours agir comme s'ils l'avaient été.) Voir cette question pour savoir pourquoi vous le pouvez. Ne définissez pas vos propres constructeurs sans paramètre sur les structures (en C #, de toute façon).

En fait, vous pouvez empêcher cette instruction si vous souhaitez écrire votre type de valeur en IL. Je viens de vérifier, et si vous vous assurez que votre type de valeur a uniquement un constructeur sans paramètre et que vous le rendez interne, vous ne pourrez pas écrire MyStruct ms = new MyStruct (); Mais cela n'empêche pas:

MyStruct[] array = new MyStruct[1];
MyStruct ms = array[0];

qui fonctionne autour de la nouvelle restriction - de sorte qu'il ne vous achète vraiment rien. C’est vraiment bien, car il serait désordonné de perdre son temps en IL.

Êtes-vous sûr de vouloir vraiment écrire une structure? Ce n'est presque jamais une bonne idée.

Autres conseils

Vous ne pouvez pas.

Toutes les valeurs d'une structure doivent être initialisées au moment de la construction, et il n'y a aucun moyen de le faire en dehors du constructeur.

Qu'est-ce que vous essayez exactement d'accomplir en faisant cela? Les structures sont des types de valeur, vous obtiendrez donc un "nouveau". struct pour la plupart des opérations. Il sera très difficile d'appliquer les types de contraintes pour lesquelles vous utiliseriez une fabrique sur une structure.

Tout le monde peut créer une structure à tout moment sans appeler de constructeur, à condition d'avoir accès à la structure. Pensez-y de cette façon:

Si vous créez un tableau d'objets avec 1 000 éléments, ils sont tous initialisés à null, ainsi aucun constructeur n'est appelé.

Avec structs, null n'existe pas. Si vous créez un tableau avec 1 000 objets DateTime, ils sont tous initialisés à zéro, ce qui correspond à DateTime.Min. Les concepteurs du moteur d’exécution ont choisi de le créer de sorte que vous puissiez créer un tableau de structures sans appeler le constructeur N fois. Un problème de performances que beaucoup de gens ne réaliseraient pas alors.

Votre idée d’usine est bonne, cependant. Est-ce que cela répondrait à votre besoin de créer une interface et de l'exposer, mais de rendre la structure privée ou interne? C’est à peu près aussi près que possible.

Mettez-le dans son propre assemblage et ayez la MyStruct () sans l'argument en tant que Internal (Friend in VB). Placez l’usine dans le même assemblage que MyStruct () mais avec un accesseur public.

Maintenant, la fabrique peut accéder à MyStruct sans argument, mais tout appel venant de l'extérieur de l'assemblage doit utiliser la fabrique.

Edit: Mon mauvais, je n'ai pas réussi à prendre en compte qu'il s'agit d'une structure. Vous ne pouvez pas faire cela avec une structure, mais seulement avec une classe. Dans ce cas, ma déclaration précédente est valable.

Vous pouvez créer une structure qui détecte si elle est dans un état initialisé par défaut, puis faire quelque chose d’approprié dans ce cas. J'ai quitté l'usine, mais un constructeur pourrait également constituer une usine adéquate dans le cas simple et commun.

C’est beaucoup de code standard. Puisque vous utilisez D, vous pensez peut-être la même chose que moi: "Je souhaite que C # ait des mixins de modèles."

Exemple:

using System;

namespace CrazyStruct
{
    public struct MyStruct
    {
        private readonly int _height;
        private readonly bool _init; // Will be 'false' using default(MyStruct).

        /// <summary>
        /// Height in centimeters.
        /// </summary>
        public int Height
        {
            get
            {
                if (!_init)
                {
                    // Alternatively, could have the preferred default value set here.
                    // _height = 200; // cm
                    // _heightInit = true;
                    throw new InvalidOperationException("Height has not been initialized.");
                }
                return _height;
            }
            // No set:  immutable-ish.
        }

        private MyStruct(int height)
        {
            _height = height;
            _init = true;
        }

        public static MyStruct Factory(int height)
        {
            return new MyStruct(height);
        }
    }

    static class Program
    {
        static void Main(string[] args)
        {
            MyStruct my = MyStruct.Factory(195);
            Console.WriteLine("My height is {0} cm.", my.Height);
            try
            {
                var array = new MyStruct[1];
                var ms = array[0];
                Console.WriteLine("My height is not {0} cm.", ms.Height);
            }
            catch (Exception ex)
            {
                Console.WriteLine("Caught the expected exception: {0}.", ex);
            }
            Console.ReadKey();
        }
    }
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top