2012-02-20 16 views
7

È possibile creare un metodo astratto che deve restituire un'istanza della classe derivata? Posso fare questo:Metodo astratto che restituisce un'istanza della classe derivata

abstract class Base 
{ 
    public abstract Base GetObj(); 
} 

class Derived : Base 
{ 
    public Derived() { } 

    public override Base GetObj() 
    { 
     return new Derived(); 
    } 
} 

ma mi chiedevo se ci fosse un modo per farlo in modo tale che Derived::GetObj() è costretto a restituire un Derived?

Grazie.

+1

Vedere: http://blogs.msdn.com/b/ericlippert/archive/2011/02/03/curiouser-and-curiouser.aspx per insidie ​​e sfide da considerare. –

+0

Grazie per il link. Lettura interessante. – Eric

risposta

16

Utilizzando farmaci generici dovrebbe rendere questo possibile:

abstract class Base<T> 
    where T : Base<T> 
{ 
    public abstract T GetObj(); 
} 

class Derived : Base <Derived> 
{ 
    public Derived() { } 

    public override Derived GetObj() 
    { 
     return new Derived(); 
    } 
} 

si potrebbe anche semplificare questo ancora di più (se tutte le istanze derivati ​​vengono creati con i costruttori di default):

abstract class Base<T> 
    where T : Base<T>, new() 
{ 
    public static T GetObj() 
    { 
     return new T(); 
    } 
} 

class Derived : Base<Derived> 
{ 
    public Derived() { } 
} 
+3

Si noti che questo impone solo la * prima * classe derivata a restituire se stessa. La seconda classe derivata può quindi restituire solo la prima. –

+0

Grazie, sembra esattamente quello di cui ho bisogno. Non credo che ci sia un modo per rendere questo un metodo statico? – Eric

+0

Sì, il metodo può essere statico, nel qual caso hai una fabbrica. E sarà in grado di usare 'Derived.GetObj()'. – Lukazoid

6

quello che hai è quasi, ma non esattamente, una fabbrica astratta. Prima dirò che dovresti lasciarlo agli implementatori delle classi derivate per farlo bene, o semplicemente fidarti che lo faranno.

Un'altra risposta ha mostrato quello che è noto come il modello di modello con ricorrenza curiosa dello . È qui che si ha una classe base che tenta di utilizzare il sistema di tipi per far sì che i tipi derivati ​​si usino in determinate posizioni di input o di output.

public abstract class Foo<T> where T : Foo<T> 
public class Bar : Foo<Bar> 

Questa idea potrebbe funzionare in altre lingue. Funziona solo in C# fino a quando le persone lo usano correttamente. Con la definizione sopra di Bar, ora posso anche avere

public class Baz : Foo<Bar> 

Che è perfettamente legale. Bar è un Foo<Bar>, che è tutto ciò che è necessario per Baz per usarlo. Nulla richiede che Baz utilizzi effettivamente lo Foo<Baz>.

Il sistema di tipi in C# non può semplicemente imporre ciò che si desidera applicare. Anche con questo modello in posizione, sei ancora nella stessa posizione di prima. Devi ancora fidarti degli implementatori delle classi derivate per farlo correttamente.

Per ulteriori informazioni su questo argomento, è possibile leggere this blog.

Problemi correlati