2012-04-15 2 views
5

내 문제는 다음과 같습니다. 분명히 작동하지 않는 홈 프로젝트의 코드 디자인을 만들었습니다. 어쩌면 "코드 냄새"가 어디에서 유래하는지 파악할 수 있습니다.추상 제네릭 형식 변수의 선언

확인을 시작하자 : 내가 아카이브 형식의 주위에 다른 종류의 포장 어떤 클래스를 정의 :

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

그 아카이브로 처리하기 위해, 나는 관리자 클래스를 정의했다. 실제로 특정 behaiour을 구현 필요한 동작을 정의 추상적 한

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(); 
     } 
    } 
} 

:

제가 이해하는 한, generic 인수는 암시 적으로 변환 될 수 없습니다. 이 문제를 해결할 방법이 있습니까? 이 코드/디자인이 "냄새"가 있습니까?

대단히 감사합니다.

+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(); } } } 

작품을 발견 비 범용 기본 클래스이거나 공변 인터페이스를 사용합니다. – CodesInChaos

+1

또한 'OpenArchive'의 서명이 잘못되었습니다. 스트림을 받아서 'T'를 반환하면 안됩니까? – CodesInChaos

답변

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

답변 해 주셔서 감사합니다. Contravariant 인터페이스가 이것을 극복하는 유일한 방법 인 것 같습니다. 그러나 나는 내 아키텍처를 전체적으로 다시 생각해야한다고 생각한다 : ( – Flagg1980

0

I이 경우에, 당신은뿐만 아니라 인수로, 방법의 반환 값으로 유형 매개 변수를 사용할 수 있습니다)

+0

'dynamic'을 사용하는 단점은 정적 유형 검사를 잃는 것이다. 메소드 이름, 메소드 서명 또는 생성자를 변경하려고 결정한 경우, 컴파일러는'동적'유형을 위해 이것을 잡아 내지 못합니다. – Michael

관련 문제