2013-07-30 7 views
8

컨텍스트 : .NET 4.0, C#C# 제네릭 및 인터페이스 구현 사용

일부 서비스를 제공하기 위해이를 구현하는 일련의 인터페이스와 클론 집합을 만들고 있습니다. 클라이언트는 구체적인 클립을 사용하지만 인터페이스를 매개 변수 유형으로 사용하여 선언 된 메소드를 호출합니다.

단순화 된 예를

는이 하나

namespace TestGenerics 
{ 
    // Interface, of fields 
    interface IField 
    { 
    } 

    // Interface: Forms (contains fields) 
    interface IForm<T> where T : IField 
    { 

    } 

    // CONCRETE CLASES 
    class Field : IField 
    { 
    } 

    class Form <T> : IForm<T> where T : IField 
    { 
    } 

    // TEST PROGRAM 
    class Program 
    { 
     // THIS IS THE SIGNATURE OF THE METHOD I WANT TO CALL 
     // parameters are causing the error. 
     public static void TestMethod(IForm<IField> form) 
     { 
      int i = 1; 
      i = i * 5; 
     } 

     static void Main(string[] args) 
     { 
      Form<Field> b = new Form<Field>(); 
      Program.TestMethod(b); 
     } 
    } 
} 

코드는 나에게 의미가 있습니다,하지만 난 컴파일러 오류 얻을 :

Argument 1: cannot convert from ' TestGenerics.Form<TestGenerics.Field> ' to ' TestGenerics.IForm<TestGenerics.IField> ' TestGenerics

내가 잘못 뭘하는지 모르겠어요를 , 나는 인터넷에서 많은 페이지를 읽었지 만 아무도 내 문제를 해결하지 못했습니다.

편집 :

내가 구축을 위해 노력하고있어의 많은 구조를 수정하지 할 수있는 솔루션이 있습니까 내가 그들을 구현 콘크리트 clases의 독립해야하도록하는 방식으로 인터페이스를 설계 . 콘크리트 클론은 dll에서로드 될 수 있지만 대부분의 어플리케이션은 인터페이스와 함께 작동합니다. 어떤 경우에는 특히 serialize해야하는 clases를 사용할 때 구체적인 clases를 사용해야합니다.

미리 감사드립니다.

알레한드로

+5

이것은 공분산의 영역에 속하는 것입니다. 특히,''out' 제네릭 수정 자 '(http://msdn.microsoft.com/en-us/library/dd469487.aspx)를 서명'interface IForm T : IField'에 추가하면 작동합니다 .그러나 이것은 다른 제한 사항/고려 사항을 추가하므로 현재 설계/사용에 적용 가능한지 여부를 말할 수 없습니다. –

+2

나는이 디자인으로 무엇을 달성하려고하는지 궁금합니다. – sidesinger

+0

두 명 모두에게 감사 드려요, 그들은 정말로 냉담했습니다. 나는 왜 그런 식으로 해결책을 가졌는지 설명하는 편집을 추가했지만, 두 사람 모두 내 문제를 해결할 수 있습니다. 문안 인사. – Sugar

답변

13

문제는 Form<Field>IForm<Field>하지만 IForm<IField> 구현하는 것입니다. 상속 된 클래스 (또는 인터페이스)는 out 식별자와 함께 공변수로 표시되어 있지 않으면 일반 매개 변수로 사용할 수 없습니다. 그러나 인터페이스를 공변으로 표시하면 사용이 크게 제한되므로 (기본적으로 "출력 전용"인터페이스 (예 : IEnumerable)로 작성) 효과가 없을 수 있습니다. 작동 갈 수

한 가지 방법은 TestMethod 일반적인뿐만 아니라 만드는 것입니다 :

public static void TestMethod<T>(IForm<T> form) where T:IField 
{ 
    int i = 1; 
    i = i * 5; 
} 
10

당신과 같이, 공분산을 사용할 수 있습니다 공분산 및 Contravariance here에 대한

interface IForm<out T> where T : IField 
{ 

} 

더.

+1

"out"키워드를 사용하여 파생 클래스를 제네릭 형식 매개 변수로 사용할 수 있도록 허용 할 때 공분산입니다. IEnumerable 인터페이스의 형식 매개 변수가 공변이므로 IEnumerable (Visual Basic에서 IEnumerable (Of 파생 됨)의 인스턴스)을 IEnumerable 유형의 변수에 할당 할 수 있으므로이 문장을 볼 수있는 게시글에 게시 된 링크에서" " –

7

다른 사람들은 오류 메시지의 원인을 지적했지만, 샘플 코드의 디자인을 잠시 살펴 보겠습니다. 아마도 아무 것도 필요없는 곳에 제네릭을 사용하고있을 수도 있습니다.

이미 IField 인터페이스에 선언 된 메서드를 사용한다고 했으므로 IForm 클래스를 범용으로 만들 필요가 없습니다. 일반 인수 'T'대신 IField에 대한 참조 만 저장하면됩니다. 어쨌든 IField로 보장됩니다).

예를 들어

는 사용

public interface IForm 
{ 
    IEnumerable<IField> Fields { get; set; } 
} 

대신

public interface IForm<T> where T : IField 
{ 
    IEnumerable<T> Fields { get; set; } 
} 
+0

동의합니다. 또 다른 표시는 소비자 코드가 IForm 및 양식 양식으로 인스턴스화하여 IField가 충분하다고 제안합니다. 진정한 테스트는 콘크리트 T 유형이 외부 지향적 인 API의 일부가되어야 할 필요가 있는지 여부와 관계가 없습니다. – Tormod