2014-09-12 21 views
7

esiste un modo per eseguire l'override covariante di "hack" o "coerce" in C#?Soluzione alternativa per mancanza di tipo covarianza di ritorno quando si annullano i metodi virtuali

Ad esempio:

public class Alpha { 
    public virtual Alpha DoSomething() { 
     return AlphaFactory.GetAlphaFromSomewhere(); 
    } 
} 
public class Beta : Alpha { 
    public override Beta DoSomething() { 
     return BetaFactory.GetBetaFromSomewhere(); 
    } 
} 

Purtroppo, C# non supporta questo (che sembra un po 'ridicolo, ma questo è né qui né là).

ho pensato che avrei potuto avere una risposta con il metodo del nascondiglio:

new public Beta DoSomething() { 
    return BetaFactory.GetBetaFromSomewhere(); 
} 

ma questo non aggiungere la voce dentro al 'vtable', dichiara appena fondamentalmente un metodo nuovo di zecca con lo stesso nome, e come tale significa che l'accesso a Beta attraverso un puntatore a un Alpha chiamerà Alpha.DoSomething().

Quindi, qualche buon trucco?

+2

Perché è necessario modificare il valore restituito? Cosa non soddisfa le tue esigenze nel fatto che 'Beta.DoSomething()' restituisca un oggetto digitato 'Alpha'? Finché i metodi giusti sono definiti come virtuali in 'Alpha' e poi sovrascritti in' Beta', non ha molta importanza; qualsiasi chiamata a un metodo virtuale si risolverà nel tipo di runtime dell'oggetto, non nel tipo di tempo di compilazione. – InBetween

+0

Non sta lanciando abbastanza di un "hack"? – Mephy

risposta

3

È possibile fare alcune cose piuttosto strane con i generici.

public class Alpha<T> where T: Alpha<T> { 
    public virtual T DoSomething() { 
     throw new NotImplementedException(); 
    } 
} 
public class Beta : Alpha<Beta> { 
    public override Beta DoSomething() { 
     throw new NotImplementedException(); 
    } 
} 
+0

Un abuso generico per ottenere esattamente cosa? – InBetween

+0

Se si ha un riferimento statico a 'Beta', non è necessario eseguire un cast di esecuzione per ottenere un riferimento' Beta' da 'DoSomething'. – recursive

+0

Oh, quindi complichi l'intero sistema di tipi con questo mal di testa generico per evitare semplicemente il cast più economico possibile (anche sicuro)? – InBetween

0

Perché nella maggior parte dei casi non c'è un grande vantaggio nella covarianza del tipo di ritorno.

Se si chiama virtuale Alpha.DoSomething allora non si sa davvero se si sta recuperando un Alpha o un Beta quindi come può aiutare la covarianza del tipo di ritorno? Dovrai memorizzare il risultato in un oggetto digitato Alpha in ogni caso perché è l'unico tipo che può ammettere Alpha s o Beta s.

D'altra parte, se si sa staticamente che si sta chiamando Beta.DoSomething allora è possibile: utilizzare direttamente il restituita Alpha oggetto tipizzato, perché vi sarà accede comune funzionalità o virtuali metodi in modo da non importa se si tratta di in realtà un Beta (la chiamata virtuale verrà risolta nel tipo giusto) oppure è possibile scegliere direttamente cast (runtime safe) su Beta per accedere all'implementazione specifica.

Modifica: rimosso il problema di tipo sicuro. Ho riflettuto a malapena e, evidentemente, il ritorno della covarianza di tipo sarebbe stato sicuro. Il resto della risposta sta comunque. Non riesco a trovare nulla di particolarmente interessante in questa funzione, almeno nel modo in cui l'OP vuole usarlo: evitare un cast sicuro a basso costo?

+0

Java può eseguire questa operazione (consente di modificare il tipo di ritorno dei metodi non finali nelle sottoclassi a condizione che il tipo restituito sia una sottoclasse del tipo restituito nella classe base). Penso che il blando licenziamento della preoccupazione dell'OP come "nessun grande beneficio" sia un po 'scoraggiante. –

+1

@KirkWoll [Tutte le caratteristiche di C# iniziano con -100 punti] (http://blogs.msdn.com/b/ericgu/archive/2004/01/12/57985.aspx), non ha ottenuto abbastanza punti. –

+0

@KirkWoll solo perché Java lo fa fuori dalla scatola non lo rende necessariamente un motivo convincente. La varianza interrotta degli array in C# è dovuta alla sua esistenza anche in Java ... è stata una buona decisione di progettazione? Potrei sbagliarmi e restituire la varianza di tipo è una grande caratteristica di avere in una lingua quindi per favore dimmi perché. Il tuo commento non è costruttivo né aggiunge nulla di utile a questo argomento. – InBetween

1

Si può sempre avvolgere il metodo all'interno di un altro metodo

public class Alpha { 
    public virtual Alpha DoSomething() { 
     return AlphaFactory.GetAlphaFromSomewhere(); 
    } 
} 
public class Beta : Alpha { 
    private Beta Helper() { 
     return BetaFactory.GetBetaFromSomewhere(); 
    } 
    public Beta DoSomething() { 
     return Helper(); 
    } 
    public override Alpha DoSomething() { 
     return Helper(); 
    } 
} 

Se ci sono un sacco di metodi, però, si potrebbe desiderare di autogenerate questi wrapper. Se è troppo impegnativo, la soluzione di @recursive è tutto ciò che rimane.