2012-04-15 17 views
5

il mio problema è il seguente. Ho realizzato un progetto di codice per un progetto di casa che apparentemente non funziona. Forse puoi aiutarmi a capire da dove viene il "codice odore".Dichiarazione di una variabile di tipo generico astratto

Ok cominciamo: ho definito alcune classi per avvolgere diversi tipi di tipi di archivio:

public abstract class Archive { } 
public class ZipArchive : Archive { } 
public class TarArchive : Archive { } 

da maneggiare con quegli archivi, ho definito le classi Manager. Un uno astratto che definisce il comportamento necessario,

public abstract class ArchiveManager<T> where T : Archive 
{ 
    public abstract void OpenArchive(T archive); 
} 

E quelli concreti, che in realtà attuare il behaiour specifica:

public class ZipArchiveManager : ArchiveManager<ZipArchive> 
{ 
    public override void OpenArchive(ZipArchive archive) { /* .. */ } 
} 

public class TarArchiveManager : ArchiveManager<TarArchive> 
{ 
    public override void OpenArchive(TarArchive archive) { /* .. */ } 
} 

Quello che succede ora è che durante la fase di compilazione, non so che tipo degli archivi che elaborerà, così ho provato la seguente:

class Program 
{ 
    static void Main(string[] args) 
    { 
     ArchiveManager<Archive> archiveManager = null; 

     if (/*some condition*/) {    
      archiveManager = new ZipArchiveManager(); 
     } 
     else { 
      archiveManager = new TarArchiveManager(); 
     } 
    } 
} 

che ha finito il seguente errore:

012.

Cannot implicitly convert type 'ZipArchiveManager' to 'ArchiveManager'

Per quanto ho capito, l'argomento generico non può essere convertito implicitamente. C'è un modo per aggirare questo? Questo codice/design "annusa"?

Grazie mille in anticipo.

+0

Creare un classe base non generica o utilizzare un'interfaccia covariante. – CodesInChaos

+1

Inoltre, la firma di 'OpenArchive' mi sembra sbagliata. Non dovrebbe ricevere un flusso e restituire 'T'? – CodesInChaos

risposta

2

È possibile utilizzare un'interfaccia controvariante anziché una classe astratta che non implementa alcuna funzionalità. In questo caso, è possibile utilizzare solo il parametro di tipo come valore di ritorno di un metodo, non come un argomento:

public interface IArchiveManager<out T> 
    where T : Archive 
{ 
    T OpenArchive(Stream stream); 
} 

Quindi, è sufficiente implementare l'interfaccia nelle classi di gestione:

public class ZipArchiveManager : IArchiveManager<ZipArchive> 
{ 
    public ZipArchive OpenArchive(Stream stream) 
    { 
     // ... 
    } 
} 

public class TarArchiveManager : IArchiveManager<TarArchive> 
{ 
    public TarArchive OpenArchive(Stream stream) 
    { 
     // ... 
    } 
} 
+0

Grazie per le vostre risposte. L'interfaccia controvariante sembra essere l'unico modo per superare questo problema. Tuttavia ritengo di dover ripensare alla mia architettura nel suo insieme :( – Flagg1980

0

I trovato un altro modo utilizzando la parola chiave "dinamica" di C# .NET 4.0 ...

class Program 
{ 
    static void Main(string[] args) 
    { 
     dynamic archiveManager = null; 

     if (/*some condition*/) {    
      archiveManager = new ZipArchiveManager(); 
     } 
     else { 
      archiveManager = new TarArchiveManager(); 
     } 
    } 
} 

funziona come un fascino per me;)

+0

Lo svantaggio dell'uso di 'dynamic' è che si perde il controllo di tipo statico.Se si decide di cambiare i nomi dei metodi, le firme dei metodi oi costruttori, il compilatore non prenderà questo per i tipi 'dinamici'. – Michael

Problemi correlati