2012-04-15 93 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