Autor Wątek: Dziedziczenie statycznego pola  (Przeczytany 3184 razy)

Offline profit

  • Użytkownik

# Wrzesień 12, 2011, 17:58:30
Witam wszystkich,

Przepraszam za nazwę tematu, wiem że statyczne składowe nie są dziedziczone osobno w każdej z klas pochodnych, ale nie potrafiłem tego inaczej nazwać :)

Problem mam następujący:
    class A
    {
        public static int EmptyID { get { return 0; } protected set { } }
        public static bool IsEmpty(int ID) { return ID == EmptyID; }
        ...
    }

    class B : A
    {
        public static new int EmptyID { get { return 1; } protected set { } }
        ...
    }

    class C : A
    {
        public static new int EmptyID { get { return 2; } protected set { } }
        ...
    }
    ...
Wiadomo że to nie działa.

Jak mogę sprawić żeby wywołanie 'IsEmpty' na obiekcie typu 'B' czy 'C' użyło wartości pola 'EmptyID' z tej konkretnej klasy, a nie bazowej?
Chciałbym żeby 'IsEmpty' pozostało statyczne i nie chcę go przepisywać w każdej klasie dziedziczącej po 'A'.

Offline Mr. Spam

  • Miłośnik przetworów mięsnych

Offline PsichiX (ΨΧΞ)

  • Użytkownik
    • PsichiX Website

# Wrzesień 12, 2011, 18:04:05
class B : public virtual A

Offline Xirdus

  • Redaktor

# Wrzesień 12, 2011, 18:05:46
@ΨΧΞ: nie ten język ;)
@OP: a po co takie kombinacje?

Offline Dab

  • Redaktor
    • blog

# Wrzesień 12, 2011, 18:27:20
Zrób EmptyID wirtualne, IsEmpty niewirtualne.

Offline gotji

  • Użytkownik

# Wrzesień 12, 2011, 20:08:35
Z tego co się orientuje to tego się nie da zrobić bo nie ma czegoś jak wirtualne pole\metoda statyczna w C#. Podejrzewam, że MSIL w ogóle nie wspiera takiego tworu i żaden z języków .Net-owych nie pozwoli na coś takiego. Możesz jednak zrobić to 'po ludzku' i załatwić to singletonem.

Offline profit

  • Użytkownik

# Wrzesień 12, 2011, 21:37:01
Zrobiłem to w okropny sposób, aż razi w oczy ta deklaracja szablonu 'A' :p
    class A<T> where T : A<T>, new()
    {
        public virtual int EmptyID { get { return 0; } protected set { } }

        public static bool IsEmpty(int ID)
        {
            T t = new T();
            return t.EmptyID == ID;
        }
        ...
    }

    class B : A<B>
    {
        public override int EmptyID { get { return 1; } protected set { } }
        ...
    }

    class C : A<C>
    {
        public override int EmptyID { get { return 2; } protected set { } }
        ...
    }
    ...
No ale działa, wywołanie 'B.IsEmpty(1)' zwraca true ;)

@gotji jeśli możesz, to rozwiń myśl z singletonem (gdzie / która klasa powinna nim być i jak miałby tu pomóc) bo z wzorcami projektowymi w jakiejkolwiek postaci nie miałem nigdy styczności :(

Offline Avaj

  • Użytkownik

# Wrzesień 12, 2011, 21:38:30
c# nie ma szablonów, ma generyki :)

Offline nembutal

  • Użytkownik

# Wrzesień 12, 2011, 23:37:44
Jako, że propozycję rozwiązań zostały już przesłane pozwolę sobie na mały flame.
    template<class A>
    class ATraits
    {
public:
                static bool IsEmpty() { return 0 == A.EmptyID; }
    };

    class B
    {
public:
static const int EmptyID = 1;
    };

    class C
    {
                public:
static const int EmptyID = 2;
    };
Ale C# się szybciej kompiluje ...
C# z tego co widzę ma żałosne wsparcie dla statycznego polimorfizmu i nie bójmy się o tym mówić zamiast w ciemno polecać ten język każdemu początkującemu.
« Ostatnia zmiana: Wrzesień 12, 2011, 23:40:59 wysłana przez nembutal »

Offline gotji

  • Użytkownik

# Wrzesień 13, 2011, 10:46:53
Więc to powinno wyglądać mniej więcej tak:

    abstract class A<T> where T : A<T>, new()
    {
        private static T instance = new T();

        protected abstract int emptyID { get; }

        public static int EmptyID
        {
            get
            {
                return instance.emptyID;
            }
        }

        public static bool IsEmpty(int id)
        {
            return instance.emptyID == id;
        }
    }

    class B : A<B>
    {
        protected override int emptyID
        {
            get
            {
                return 1;
            }
        }
    }

    class C : A<C>
    {
        protected override int emptyID
        {
            get
            {
                return 2;
            }
        }
    }

    ...
    B.IsEmpty(1);  // True
    C.IsEmpty(2);  // True
    ...

 Krótko o co chodzi:
- Wszystkie pola\metody statyczne są trzymane w definicji klasy i jeżeli klasa jest dziedziczona kilka razy to i tak wartości są trzymane w jednym miejscu -> zmiana jakiejś wartości = nadpisanie poprzedniej. Żeby to wyeliminować potrzebna jest klasa bazowa, która będzie generyczna. Klasa generyczna dla każdej różnej wartości T stworzy oddzielną definicję klasy bazowej: definicja A<B> != definicja A <C>, dzięki temu przechowywane wartości klasy dziedziczącej po niej nie będą nadpisywane.

- Po przez 'constraint-y' w definicji klasy bazowej na typie T. Wymuszamy żeby T dziedziczyło po klasie bazowej, oraz żeby miało bezparametrowy konstruktor. Dzięki tym 'ograniczeniom' możemy się posługiwać typem T bardziej swobodnie.

- Klasa bazowa przechowuje obiekt typu T dzięki czemu nie musimy za każdym razem tworzyć obiektu aby wykonać metodę statyczną.

Offline profit

  • Użytkownik

# Wrzesień 13, 2011, 12:12:52
Dobra, dzięki za wyjaśnienie :)
Zrezygnowałem jednak ze statycznych pól/metod (nie wiem czy dobrze zrobiłem, ale nie są mi aż tak bardzo potrzebne), EmptyID oraz IsEmpty są teraz instancyjne dla każdego obiektu.

Myślę że problem rozwiązany.

Offline gotji

  • Użytkownik

# Wrzesień 13, 2011, 13:01:09
Dobra, dzięki za wyjaśnienie :)
Zrezygnowałem jednak ze statycznych pól/metod (nie wiem czy dobrze zrobiłem, ale nie są mi aż tak bardzo potrzebne), EmptyID oraz IsEmpty są teraz instancyjne dla każdego obiektu.

Myślę że problem rozwiązany.

Wydaje mi się że słuszna decyzja. Pewnie można znaleźć wiele lepszych rozwiązań aby osiągnąć to co próbujesz.

Ale C# się szybciej kompiluje ...
C# z tego co widzę ma żałosne wsparcie dla statycznego polimorfizmu i nie bójmy się o tym mówić zamiast w ciemno polecać ten język każdemu początkującemu.
Nie ma żałosnego wsparcia, tylko po prostu  nie ma czegoś takiego jak statyczny polimorfizm(w ogóle jak to brzmi?) w C#. Klasy statyczne są domyślnie 'sealed'. Nie postrzegam tego jako wadę języka bo polimorfizm kojarzy się z czymś dynamicznym, a nie statycznym. Co do polecani go ludziom początkującym to też nie wydaje mi się to dobrym rozwiązaniem.  Zawsze wyznawałem zasadę, że najpierw: ELI(schematy blokowe) -> Assembler -> Języki wysokiego poziomu.