2009-11-06 3 views
5

Voglio fare un'interfaccia in C# che definisce un metodo che restituisce sempre un oggetto della classe che implementa, in tal modo:Posso forzare una classe di implementazione per restituire un oggetto del proprio tipo?

public interface IParser { 
    IParser Parse(string s); 
} 

public class Parser : IParser { 
    public Parser Parse(string s) { 
     return new Parser(s); 
    } 
} 

Posso forzare una classe di implementazione per restituire un oggetto del proprio tipo? Se possibile, quindi come? O i generici sono la risposta qui?

NB: Il codice è solo un esempio, non è qualcosa che dovrebbe funzionare.

+0

Mi hai reso molto curioso: perché stai provando a fare questo? Generalmente, il punto di definire un'interfaccia è che il codice client possa fidarsi che una determinata API sia definita su un oggetto senza dover sapere o preoccuparsi di quale sia il tipo concreto di quell'oggetto. Questo è uno dei grandi punti di forza dell'OOP. Che cosa stai cercando di ottenere facendo questo? –

+0

Beh, il mio pensiero era che avendo questa interfaccia si poteva sempre avere fiducia che le classi che implementano l'interfaccia avessero questo metodo e che restituissero sempre il loro tipo. Ma come dici tu, questo potrebbe non essere il miglior design OO e lo abbandonerò per un metodo che restituisce invece il tipo di interfaccia. – Cros

risposta

8

Generics è la risposta Qui.

public interface IParser<T> where T:IParser<T> { 
    T Parse(string s); 
} 

public class Parser : IParser<Parser> { 
    public Parser Parse(string s) { 
     return new Parser(s); 
    } 
} 
+0

Buon lavoro ... Stavo solo testando il mio codice per la stessa cosa. +1 – jheddings

+0

Lo proverò immediatamente. – Cros

+0

Sembra che quando si rende l'interfaccia generica come questa, è necessario specificare T ovunque si usi ISelection come identificatore per il tipo che si utilizza, ad es. Non riesco ora a creare solo una lista ma ora deve essere una lista >. Ho ragione? Quindi questa non è la soluzione che sto cercando, purtroppo. – Cros

1

Sì, e questo è noto come the factory pattern, solo che di solito questo è completato con l'uso di un costruttore privato e rendendo l'istanza di metodo che restituisce statico, ad esempio:

public class Parser : IParser { 

    private Parser(string s) { 
     //Do something with s, probably store it in a field 
    } 

    public static IParser GetNewParser(string s) { 
     return new Parser(s); 
    } 
} 
+0

Penso che la chiave sia la frase "... forza una classe di implementazione a restituire un oggetto del proprio tipo ..." –

+0

Questa non era una domanda "si/no". Voglio sapere concretamente come si fa in C#, se è possibile. – Cros

0

È possibile farlo con i generici, ma avrei probabilmente bastone con il ritorno un'istanza dell'interfaccia. Nota che poiché la classe implementa l'interfaccia, restituire un'istanza di esso è ok, sarà anche un'istanza di quel tipo e dell'interfaccia.

public class Parser : I Parser 
{ 
    public IParser Parser(string s) 
    { 
     return Parser(s); 
    } 
} 
5

Non nella dichiarazione di interfaccia, n. Il meglio che si potrebbe gestire è con i generici:

public interface IParser<T> 
    where T: IParser<T> 
{ 
    T Parse(string s); 
} 

public class Parser 
: IParser<Parser> 
{ 
    public Parser Parse(string s) 
    { 
     return new Parser(s); 
    } 
} 

Questo non forza l'attuazione di tornare il suo tipo, ma almeno permette di farlo. Questo è il motivo per cui l'interfaccia IClonable restituisce un oggetto dal suo metodo Clone, piuttosto che un tipo specifico.

---- ---- Edit

Qualcosa da ricordare su questa questione: diciamo che il mio codice, per i quali non si dispone di alcuna conoscenza della realizzazione, restituisce un IParser, e il codice chiama il metodo Parse. Quale oggetto ti aspetti di ricevere, non conoscendo il tipo concreto di riferimento IParser restituito? Penso che tu stia cercando di usare le interfacce per qualcosa che non dovrebbero fare ...

+1

+1 per aver menzionato questa tecnica non impone l'implementazione richiesta. Si potrebbe facilmente restituire un'altra implementazione di IParser . AFAIK non è possibile applicare questo controllo a livello di lingua; questa è la cosa più vicina che otterrai. –