2013-07-02 14 views
5

Ok, ho un numero di classi diverse derivate da una classe base. Questa classe base è un abstract contenente i metodi del comando.Usa il tipo derivato nella classe astratta base

Uno dei metodi è un metodo Copy, che dovrebbe essere presente in tutte le classi derivate, quindi l'ho inserito nella classe base. MA, voglio che restituisca il derived type non la base né l'oggetto.

La soluzione che ho avuto per questo, sta utilizzando un tipo paramter:

abstract class CopyableClass<T> 
{ 
    public abstract T Copy(); 
} 

class DerivedClass : CopyableClass<DerivedClass> 
{ 
    public override DerivedClass Copy() 
    { 
     //do what is needed for copy and return a new DerivedClass 
    } 
} 

Quindi, lo scopo principale è quello di

Rimuovere il parametro di tipo nella classe di base e ancora fare il metodo restituisce il tipo derivato corrispondente.


Una soluzione.

La cosa migliore che potessi fare finora è uno dei commenti qui sotto, ma utilizza ancora un parametro generico

abstract class BaseClass 
{ 
    //base methods not related to deriving type 
} 

interface ICopyable<T> 
{ 
    T Copy(); 
} 

class DerivedClass : BaseClass, ICopyable<DerivedClass> 
{ 
    public DerivedClass Copy() 
    { 
     //do what is needed for copy and return a new DerivedClass 
    } 
} 
+0

Allora, qual è la tua domanda? – evanmcdonnal

+0

potrebbe essere meglio implementarlo come interfaccia generica? –

+0

come rimuovere il parametro type nella classe base e continuare a restituire il metodo derivato corrispondente. –

risposta

4

non si può davvero. La classe base non può probabilmente conoscere tutte le future implementazioni. Dovrai ricorrere a un tipo di classe astratta generico (come hai fatto tu) o un metodo generico Copy.

public abstract class CopyableClass 
{ 
    public abstract T Copy<T>() where T : CopyableClass; 
} 

public class DerivedClass : CopyableClass 
{ 
    public override T Copy<T>() 
    { 
     if(typeof(T) != typeof(DerivedClass)) 
      throw new ArgumentException(); 

     // return your copy 
    } 
} 

Oppure, se si vuole generalizzare il controllo di tipo nella classe base:

public abstract class CopyableClass 
{ 
    public T Copy<T>() where T : CopyableClass 
    { 
     if(GetType() != typeof(T)) 
      throw new ArgumentException(); 

     return (T) Copy(); 
    } 

    protected abstract CopyableClass Copy(); 
} 

public class DerivedClass : CopyableClass 
{ 
    protected override CopyableClass Copy() 
    { 
     return // Your copy; 
    } 
} 

Nota che il secondo metodo mette un sacco di fiducia nella implementazione della classe derivata in quanto sarà cieca cast il valore di ritorno del metodo astratto. Il compilatore ti permetterà di restituire un altro tipo, implementando CopyableClass, in un tipo derivato ma sarà un errore di runtime. Questo non è un problema se si ha il controllo assoluto su tutte le implementazioni derivate (cioè la classe astratta ha anche un costruttore interno).

0

In realtà si desidera implementare la copia nella classe base e restituirla T. Questo farà sì che tu lo chiami con un argomento di tipo e restituisca quel tipo.

public static T Copy<T>() where T : CopyableClass 
{ 
    T retVal = new T(); 
    // do whatever copying is required 
    return retVal; 
} 

Per chiamarlo come si fa;

DerivedClass d = Copy<DerivedClass>(); 

il codice per eseguire la copia in realtà potrebbe essere un po 'più di lavoro per rendere generico, ma ne vale la pena data si avrà una singola implementazione di Copy() che funziona per qualsiasi tipo derivato. Non so quale logica appartenga al metodo, quindi ho appena eliminato le cose. Inoltre, mi consiglia di controllare generici in generale. Sono spesso l'opzione migliore per cose come questa. Se le implementazioni devono essere univoche per la classe base 'mantenere la stessa definizione del metodo ma renderla astratta e quindi sovrascriverla nelle classi base.

0

Ciò consentirà di assegnare questa classe di base al tipo derivato e di restituirla.

public abstract class BaseClass<TDerived> : where TDerived: BaseClass<TDerived> 
{ 
    public TDerived DoSomethingCommon(string param) 
    { 
     var derivedType = (TElement)this; 
     //do something. 
     return derivedType; 
    } 
} 
0

Questa soluzione riguarda una classe media, ma penso che sia più in linea con quello che stai cercando. Almeno hai il vantaggio di isolare il tuo codice copia

public abstract class BaseClass 
    { 
    } 

    public abstract class CopyableClass<T> : BaseClass 
     where T: BaseClass, new() 
    { 
     public T Copy() 
     { 
      var copy = new T(); // Creating a new instance as proof of concept 

      return copy; 
     } 
    } 

    public class DerivedClass : CopyableClass<DerivedClass> 
    { 
    } 
Problemi correlati