Struktura i metoda w niej

Struktura i metoda w niej
  • Rejestracja: dni
  • Ostatnio: dni
0

Cześć.
Mam mały problem.
Mam strukturę RGB, gdzie przechowuję jak się domyślacie, wartości składowych RGB.

Kopiuj
struct RGB
{
        private const int MIN_RGB_VALUE = 0;
        private const int MAX_RGB_VALUE = 255;
        public int A;
        public int R;
        public int G;
        public int B;

        public RGB(int r, int g, int b)
        {
            this.A = MAX_RGB_VALUE;
            this.R = r;
            this.G = g;
            this.B = b;
        }
}

I działa ok, jednak konstruktorów w tej strukturze mam więcej. Np z parametrami (int a, int r, int g, int b), (int r, int g, int b) oraz (RGB rgb).

I teraz w każdej strukturze muszę robić tak:

Kopiuj
public RGB(int r, int g, int b)
        {
            this.A = MAX_RGB_VALUE;
            this.R = r;
            this.G = g;
            this.B = b;
        }

        public RGB(int a, int r, int g, int b)
        {
            this.A = a;
            this.R = r;
            this.G = g;
            this.B = b;
        }

        public RGB(RGB rgb)
        {
            this.A = rgb.A;
            this.R = rgb.R;
            this.G = rgb.G;
            this.B = rgb.B;
        }

Co powoduje, że powielam cały czas jeden i ten sam kod - przypisywania.
Toteż napisałem funkcję:

Kopiuj
public void SetRGB(int r, int g, int b)
        {
            R = r;
            G = g;
            B = b;
        }

        public void SetARGB(int a, int r, int g, int b)
        {
            SetRGB(r, g, b);
            this.SetAValue(a);
        }

Ale, gdy dodaję ją w konstruktorze to wywala mi błąd:

Kopiuj
public RGB(int r, int g, int b)
        {
            this.SetARGB(MAX_RGB_VALUE, r, g, b);
        }

The 'this' object cannot be used before all of its fields are assigned to
Field 'Program.RGB.A' must be fully assigned before control leaves the constructor
Field 'Program.RGB.R' must be fully assigned before control leaves the constructor
Field 'Program.RGB.G' must be fully assigned before control leaves the constructor
Field 'Program.RGB.B' must be fully assigned before control leaves the constructor

Moje pytanie brzmi:
Czy można w konstruktorze struktury wywołać funkcję przypisania bez wcześniejszego powielania tego kodu?
Chciałbym po prostu stworzyć takie konstruktory:

Kopiuj
public RGB(int r, int g, int b)
        {
            this.SetARGB(MAX_RGB_VALUE, r, g, b);
        }

        public RGB(int a, int r, int g, int b)
        {
            this.SetARGB(a, r, g, b);
        }

        public RGB(RGB rgb)
        {
            this.SetARGB(rgb.A, rgb.R, rgb.G, rgb.B);
        }

Niestety wywołuje to błędy. Jeśli w taki sposób nie jest to możliwe to dlaczego?
Dlaczego w strukturze nie jest to możliwe, a w klasie tak?

Z góry dziękuję za odpowiedź.

msm
  • Rejestracja: dni
  • Ostatnio: dni
2

Po pierwsze, nie do końca związane z tematem -

Kopiuj
        private const int MIN_RGB_VALUE = 0;
        private const int MAX_RGB_VALUE = 255;
        public int A;
        public int R;
        public int G;
        public int B;

Bardzo marnujesz pamięć w ten sposób. Zamiast 4 bajtów, twój kolor zajmuje 16. Dodatkowo męczysz się z maksymalnymi i minimalnymi wartościami. Z tego też powodu, robienie z tego struktury zaczyna mieć małe uzasadnienie:

Moja propozycja:

Kopiuj
    struct RGB
    {
        public byte A;
        public byte R;
        public byte G;
        public byte B;

        public RGB(byte r, byte g, byte b)
        {
            this.A = byte.MaxValue; // i nie potrzeba stałych
            this.R = r;
            this.G = g;
            this.B = b;
        }
    }

Ew. jeśli chcesz mieś w publicznym interfejsie inty

Kopiuj
struct RGB
{
    private byte a;
    private byte r;
    private byte g;
    private byte b;

    public RGB(int r, int g, int b)
    {
        this.a = byte.MaxValue;
        this.r = (byte)r;
        this.g = (byte)g;
        this.b = (byte)b;
    }

    public int A { get { return a; } set { a = (byte)value; } }
    public int R { get { return r; } set { r = (byte)value; } }
    public int G { get { return g; } set { g = (byte)value; } }
    public int B { get { return b; } set { b = (byte)value; } }
}

Ok, a teraz do rzeczy.

Kopiuj
        public RGB(int r, int g, int b)
        {
            this.SetARGB(MAX_RGB_VALUE, r, g, b);
        }
 
        public RGB(int a, int r, int g, int b)
        {
            this.SetARGB(a, r, g, b);
        }
 
        public RGB(RGB rgb)
        {
            this.SetARGB(rgb.A, rgb.R, rgb.G, rgb.B);
        }

Można to rozwiązać w dość kiepski sposób tak:

Kopiuj
        public RGB(int r, int g, int b) : this()
        {
            this.SetARGB(MAX_RGB_VALUE, r, g, b);
        }
 
        public RGB(int a, int r, int g, int b) : this()
        {
            this.SetARGB(a, r, g, b);
        }
 
        public RGB(RGB rgb) : this()
        {
            this.SetARGB(rgb.A, rgb.R, rgb.G, rgb.B);
        }

Wytłumaczenie - zanim możesz wywołać jakąś metodę struktury, wszystkie jej pola muszą być przez Ciebie wypełnione. Zapewnia to właśnie : this() które wywołuje konstruktor dymyślny wypełniający wszystko zerami.

Ale da się lepiej.
Istnieje do tego ciekawa konstrukcja, pozwalająca jednym konstruktorom wywoływać inne konstruktory tej samej klasy. Przed chwilą była zresztą zaprezentowana - this(parametry) - w taki sposób, możesz rozwiązać swój problem tak:

Kopiuj
        public RGB(byte a, byte r, byte g, byte b)
        {
            this.A = a;
            this.R = r;
            this.G = g;
            this.B = b;
        }

        public RGB(byte r, byte g, byte b)
            : this(byte.MaxValue, r, g, b) { }

        public RGB(RGB rgb)
            : this(rgb.A, rgb.R, rgb.G, rgb.B) { }
  • Rejestracja: dni
  • Ostatnio: dni
0

Baaaaaaaaaaaaardzo dziękuję!
Naprawdę mi pomogłeś. Lepiej wytłumaczyć się tego nie dało :)

ps: O tych bajtach to ja wiedziałem ,tylko, że w tej strukturze dodawać będę liczby do składowych, przez co byte przekroczy zakres, więc jest int.

Azarien
  • Rejestracja: dni
  • Ostatnio: dni
0

jeśli zamierzasz gdzieś pobierać do tej struktury wskaźnik, albo przekazywać do kodu natywnego – należałoby dodać StructLayout jeszcze:

Kopiuj
[StructLayout(LayoutKind.Sequential)]
struct RGB
{
  ...
}

Zarejestruj się i dołącz do największej społeczności programistów w Polsce.

Otrzymaj wsparcie, dziel się wiedzą i rozwijaj swoje umiejętności z najlepszymi.