2012-04-15 96 views
5

我的問題如下。我爲一個顯然不工作的家庭項目做了代碼設計。也許你可以幫我弄清楚「代碼味道」來自哪裏。抽象泛型類型變量的聲明

好了,讓我們開始: 我已經定義了一些類環繞不同類型的檔案類型:

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

與那些檔案處理,我定義的管理類。 一個抽象定義所需的行爲,

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

和具體的,實際實現的具體行爲體:

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

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

什麼,現在的情況是,在編譯的時候,我不知道是什麼樣檔案我會處理的,所以我試過如下:

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

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

從而結束了以下錯誤:

Cannot implicitly convert type 'ZipArchiveManager' to 'ArchiveManager'

據我所知,泛型參數不能隱式轉換。有什麼辦法可以解決這個問題嗎?這個代碼/設計是否「聞」?

非常感謝您提前。

+0

創建非泛型基類,或使用協變接口。 – CodesInChaos 2012-04-15 09:29:31

+1

另外,'OpenArchive'的簽名對我來說看起來是錯誤的。它不應該收到一個流,並返回'T'? – CodesInChaos 2012-04-15 09:30:44

回答

2

您可以使用反變換接口來代替不實現任何功能的抽象類。在這種情況下,你只能使用類型參數作爲方法的返回值,而不是作爲一個參數:

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

然後,只需實現你的管理類接口:

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

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

謝謝你的回答。反變化界面似乎是克服這一問題的唯一方法。但是我相信我必須重新考慮我的架構作爲一個整體...... :( – Flagg1980 2012-04-17 15:14:37

0

我發現使用C#.NET 4.0的「動態」關鍵字的另一種方式......

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

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

作品對我來說就像魅力;)

+0

使用'dynamic'的缺點是您失去了靜態類型檢查,如果您決定更改方法名稱,方法簽名或構造函數,編譯器不會爲'dynamic'類型捕獲這個。 – Michael 2012-05-02 10:03:56