2012-08-05 15 views
5

Proszę spojrzeć na moją strukturę klasową. Myślę, że chciałbym mieć więcej zabawy z dziedziczeniem, niż to jest możliwe.C# - zaawansowane dziedziczenie

Pierwszy znajduje się baza klasa abstrakcyjna:

public abstract class PolicyDetailed 
{ 
    internal abstract DataContainer GetActiveAsset(); 
} 

Następny tam jest inna klasa abstrakcyjna, która jest nazwą rodzajową:

public abstract class PolicyDetailed<T> : PolicyDetailed where T : DataContainer 
{ 
    internal new abstract T GetActiveAsset(); 
} 

Wreszcie istnieje konkretna klasa polityka. AccidentContainer dziedziczy DataContainer:

public class PolicyAccident : PolicyDetailed<AccidentContainer> 
{ 
    internal override AccidentContainer GetActiveAsset() 
    { 
     return null; 
    } 
} 

Podczas kompilacji dostaję następujący błąd:

'PolicyAccident' does not implement inherited abstract member 'PolicyDetailed.GetActiveAsset()' 

Nie jestem pewien, co modyfikatory należy użyć, żeby zmusić go do pracy. Może powinienem również napisać, co chciałbym osiągnąć: Mam kolekcję obiektów polityki różnych typów (np. PolicyAccident, PolicyTravel itp.), Które dziedziczą z PolicyDetailed z różnymi typami DataContainer (AccidentContainer, TravelContainer itp.). Chciałbym nazwać metodę "GetActiveAsset" na każdym z nich bez znajomości ich specyficznego typu i odnoszenia ich za pomocą PolicyDetailed. W tym samym czasie chciałbym, aby każda klasa zwracała swoją specyficzną podklasę Datacontainer. Czy to jest możliwe?

+0

Czy naprawdę ważne jest, aby zadeklarować, że określone typy kontenerów zwracają określone typy polis? Mówisz, że chcesz odwołać zwrócone obiekty jako PolicyDetailed, i w ten sposób i tak tracisz określone informacje! (Pamiętaj, że AccidentContainer _IS_ a DataContainer i AccidentContainer mogą zostać zwrócone z metody z typem danych zwrotnych DataContainer bez zmiany jakiegokolwiek podpisu) – olagjo

+0

Potrzebuję go w innych częściach kodu, gdzie odwołuję się do określonego typu polityki i używam jej secific container. Mogę rozważyć użycie dwóch metod - jeden zwróci obiekt DataContainer, drugi może zwrócić konkretny kontener (ale wydaje się trochę niezręczny :() – Rummy

Odpowiedz

6

Problem polega na tym, że nie można zastąpić nietypowej metody w tej samej klasie, co w przypadku deklarowania innej metody z tą samą sygnaturą.

Istnieje kilka opcji:

  • Zdecydowanie najprostszym jest dać dwóch metod różne nazwy. Następnie można podać implementację w PolicyDetailed<T> który tylko delegaci do nowej metody abstrakcyjne:

    public abstract class PolicyDetailed 
    { 
        internal abstract DataContainer GetActiveAsset(); 
    } 
    
    public abstract class PolicyDetailed<T> : PolicyDetailed where T : DataContainer 
    { 
        internal abstract T GetActiveAssetGeneric(); 
    
        internal override DataContainer GetActiveAsset() 
        { 
         return GetActiveAssetGeneric(); 
        } 
    } 
    
    public class PolicyAccident : PolicyDetailed<AccidentContainer> 
    { 
        internal override AccidentContainer GetActiveAssetGeneric() 
        { 
         return null; 
        }  
    } 
    
  • Ty mógłby wprowadzić inny poziom dziedziczenia, wprowadzając nową nazwę metody tylko dla celów pomostowych. Jest to dość brzydki:

    public class DataContainer {} 
    public class AccidentContainer : DataContainer{} 
    
    public abstract class PolicyDetailed 
    { 
        internal abstract DataContainer GetActiveAsset(); 
    } 
    
    // This only exists to satisfy the base class abstract member, 
    // but at the same time allowing PolicyDetailed<T> to introduce 
    // a new member with the same name. 
    public abstract class PolicyDetailedBridge<T> : PolicyDetailed 
        where T : DataContainer 
    { 
        protected abstract T GetActiveAssetGeneric(); 
    
        internal override DataContainer GetActiveAsset() 
        { 
         return GetActiveAssetGeneric(); 
        } 
    } 
    
    public abstract class PolicyDetailed<T> : PolicyDetailedBridge<T> 
        where T : DataContainer 
    { 
        protected sealed override T GetActiveAssetGeneric() 
        { 
         // Call the *new* abstract method. Eek! 
         return GetActiveAsset(); 
        } 
    
        internal abstract new T GetActiveAsset(); 
    } 
    
    public class PolicyAccident : PolicyDetailed<AccidentContainer> 
    { 
        internal override AccidentContainer GetActiveAsset() 
        { 
         return null; 
        }    
    } 
    
  • Można zrobić non-generic PolicyDetailed klasa interfejs zamiast i używać wyraźny wdrożenie interfejsu zadeklarować nową metodę abstrakcyjną i nadal implementować interfejs.