Frage

Ich habe eine C#-Struktur, in der ich den Aufruf des No-Args-Konstruktors verbieten muss.

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

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

Ich mache das hauptsächlich, um explizite Werte für alle Mitglieder zu erzwingen, da es keine gültigen Standardwerte gibt und alle Mitglieder gültige Werte haben müssen.

In C++ wäre das einfach, fügen Sie einen privaten Konstruktor hinzu, aber C# lässt das nicht zu.

Gibt es eine Möglichkeit, das oben Genannte zu verhindern?

Ich muss wirklich die Verwendung einer Factory erzwingen, damit das Verhindern aller öffentlichen Konstruktoraufrufe genauso gut funktioniert.


Vollständige Offenlegung:Um eine Monoabhängigkeit zu vermeiden, wird die C#-App automatisch in D übersetzt new Struct() führt zu einem Zeiger und das bringt für mich alles durcheinander.Diese Frage ist jedoch trotzdem relevant, also ignorieren Sie sie einfach.

War es hilfreich?

Lösung

Sie können nicht. Alle Strukturen haben einen öffentlichen parameterlosen Konstruktor per Definition in C #. (In der CLR fast keiner von ihnen tun, aber sie können immer so handeln, wenn sie haben.) Siehe diese Frage, warum können Sie ‚t Ihre eigenen parameterlos Konstrukteuren auf structs definieren (in C #, sowieso).

In der Tat, Sie können verhindern diese Aussage, wenn Sie gerne Ihre Werttyp in IL zu schreiben. Ich habe gerade überprüft, und wenn Sie sicherstellen, dass Ihr Wert eingeben hat nur einen parameterlosen Konstruktor, und es intern machen, werden Sie nicht in der Lage sein MyStruct ms = new MyStruct(); schreiben Aber das verhindert nicht:

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

, die um die neue Beschränkung funktioniert - so ist es nicht wirklich Sie etwas kaufen. Das ist eigentlich ganz gut, wie um in IL Unordnung wäre chaotisch.

Sind Sie sicher, dass Sie wirklich eine Struktur in erster Linie sein wollen zu schreiben? Das ist fast nie eine gute Idee.

Andere Tipps

Sie können es nicht.

Alle Werte in einer Struktur muss Bauzeit initialisiert werden, und es gibt keine Möglichkeit, dass außerhalb des Konstruktor zu tun.

Was genau wollen Sie, indem Sie das erreichen? Structs sind Werttypen, so dass Sie eine „neue“ Struktur für die meisten Operationen erhalten. Es wird sehr schwierig sein, die möglichen Einschränkungen erzwingen Sie eine Fabrik für auf einer Struktur verwenden würden.

Jeder kann jederzeit eine Struktur erstellen, ohne einen Konstruktor aufzurufen, solange er Zugriff auf die Struktur hat.Stellen Sie sich das so vor:

Wenn Sie ein Array von Objekten mit 1000 Elementen erstellen, werden alle auf Null initialisiert, sodass keine Konstruktoren aufgerufen werden.

Bei Strukturen gibt es so etwas wie null nicht.Wenn Sie ein Array mit 1000 DateTime-Objekten erstellen, werden alle auf Null initialisiert, was DateTime.Min entspricht.Die Designer der Laufzeit haben sich dafür entschieden, es so zu gestalten, dass Sie ein Array von Strukturen erstellen können, ohne den Konstruktor N-mal aufzurufen – ein Leistungseinbruch, von dem viele Leute nicht wussten, dass er da war.

Ihre Fabrikidee ist allerdings gut.Würde es Ihren Anforderungen entsprechen, eine Schnittstelle zu erstellen und diese verfügbar zu machen, die Struktur jedoch privat oder intern zu machen?Das ist ungefähr so ​​nah wie möglich.

Legen Sie es in seine eigene Montage und haben die MyStruct () ohne die args als Internal (Freund in VB). Habe die Fabrik in der gleichen Anordnung wie MyStruct (), aber mit einem öffentlichen Accessor.

Nun kann die Fabrik, die keine args MyStruct zugreifen, aber alles, was von außerhalb der Versammlung anrufen, muss die Fabrik verwendet werden.

Edit: Meine schlecht, ich nicht zu berücksichtigen, dass dies eine Struktur ist. Sie können dies nicht mit einer Struktur, nur mit einem Klasse -. In diesem Fall meine vorherige Aussage steht

Sie könnten eine Struktur machen, der erkennt, wenn es in einem Standard initialisierten Zustand ist, und dann etwas falls in diesem Fall tun. Ich verließ die Fabrik in, aber ein Konstruktor könnte auch eine angemessene Fabrik in dem gemeinsamen, einfachen Fall sein.

Es ist eine Menge Standardcode. Da Sie D verwenden, können Sie das gleiche denken, ich bin, „wünsche ich C # Vorlage Mixins hatte.“

Beispiel:

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();
        }
    }
}
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top