2012-02-18 5 views
2

내가 갖는 특정 예외입니다 :수 없습니다 <object>

tag = (INbtTag<object>)new NbtByte(stream); 
:

캐스팅 할 수 없습니다 유형 NbtByte의 객체가이 행에 INbtTag<System.Object>

를 입력

여기에서 tag은 다음과 같이 선언됩니다.

INbtTag<object> tag; 

그리고 NbtByte는 다음과 같이 정의된다 :

public interface INbtTag<out T> 

은 내가 이런 식으로 일을 할 수있을 것 out T로 선언하여 생각 : IBtTag

public class NbtByte : INbtTag<byte> 

.

는 기본적으로, 나는

var dict = new Dictionary<string, INbtTag<object>>(); 

IbtTag<T>의 사전을 갖고 싶어하지만 T는 다른 유형의이다 (따라서 나는 object으로 선언). 이것이 가능한가?

답변

7

인터페이스 차이는 참조 유형에만 적용됩니다. 값 유형 (예 : int, 바이트 등 사용자 정의 구조체)은 제외됩니다. 예를 들어 배열이 IEnumerable<int>인데도 정수 배열을 IEnumerable<object>으로 사용할 수 없습니다.

IEnumerable<object> objs = new int[] { 1, 2, 3 }; // illegal 
IEnumerable<object> objs = new string[] { "a", "b", "c" }; // legal 

사전을 사용하여 문제를 해결하려면 비 제네릭 인터페이스를 정의하는 것이 좋습니다. (제네릭 인터페이스 유형 T 같은 멤버를 노출 될 경우, 제네릭이 아닌 인터페이스는 단순히 object를 노출합니다.)

interface INbtTag { } // non-generic interface 
interface INbtTag<out T> : INbtTag { } // covariant generic interface 

는 그런 다음 Dictionary<string, INbtTag>로 사전을 사용할 수 말해봐.

단점은 인터페이스를 구현할 때 을 모두 구현해야한다는 것입니다. 일반적으로 이는 제네릭 버전을 암시 적으로 구현하고 비 제네릭을 명시 적으로 구현하는 것을 의미합니다. 예를 들면 다음과 같습니다.

+0

원래 그랬지만 비 제너릭은 내가 원했던 "Value"속성을 잃어 버렸습니다. 어떻게 그것을'객체'로 드러내고 타입을'T '로 "오버라이드"합니까? 아마도'new' 키워드를 사용하고 있을까요? – mpen

+0

구현 샘플의 업데이트를 참조하십시오. –

+0

아 ... 그 이유는 내가 IEnumerables로 그 패턴을 해왔다는 것입니다! 나는'T GetValue()'에'new' 키워드가 필요하다고 생각합니다. 그것은 꽤 아니지만, 우리가 할 수있는 최선의 방법이라고 생각합니다. 당신의 도움을 주셔서 감사합니다! – mpen

1

제네릭 형식을 사용하는 데있어 제한적인 측면 중 하나는 제네릭 형식이 기존 형식처럼 형식 변환에서 유연성이 없다는 것입니다. List<Object>List<String> 또는 기타 모든 개체 유형과 할당 호환되지 않습니다.

.Cast<T>()과 같은 Linq에는 하나의 목록에서 T 유형으로 모든 요소를 ​​논리적으로 캐스팅하여 List<T> 유형의 새 목록을 만드는 변환 도우미 함수가 있습니다. 도우미 기능이 편리하지만 N과 T가 형식에 따라 호환되는 경우에도 List<N>List<T>과 호환되지 않는다는 사실은 변경되지 않습니다.

본질적으로 제네릭 유형은 다형성이 아닙니다. 동일한 제네릭 형식의 인스턴스 간에는 일반적인 형식이 없습니다. List<T>List<N>을 포함 할 수있는 변수를 선언 할 수있는 형식이 없습니다.

자신 만의 제네릭 유형을 만들고 일반 유형의 모든 표현을 수행하는 데 사용할 수있는 공통 유형을 원한다면 작동시키기 위해 일부 유형의 체조를 수행해야하며 당신이 할 수있는 일이 제한 될 것입니다. 기본 클래스 또는 인터페이스 유형을 정의해야하며 그런 다음 일반 유형을 기본 클래스에서 상속 받거나 인터페이스 유형을 구현해야합니다. 이 구성을 사용하면 기본 클래스 유형 또는 인터페이스 유형으로 변수를 선언 할 수 있으며 MyClass<N>MyClass<T>을 동일한 변수에 할당하여 기본 클래스에 정의 된 멤버 만 액세스 할 수 있습니다 (물론 N 또는 T 형 매개 변수).

공변량 유형 매개 변수 (IMyInterface<out T>)는 거기에 참여할 수 있지만 공분산은 해당 인터페이스에서 수행 할 수있는 작업에 심각한 제한을 설정합니다. 공변 유형 T는 함수 결과에만 사용할 수 있고 인수 또는 설정 가능한 속성에는 사용할 수 없습니다 .

IList<T>이 공변 (covariant)으로 선언되지 않았다는 단순한 사실은 우연이나 감독이 아니며 공변 할 수 없습니다. 유용하게 사용하려면 IList<T>에는 T가 공 변성 일 때 금지되는 Add (T item) 및 Remove (T item)와 같은 메소드가 필요합니다.

+0

공분산에 제한이 있다는 것을 인식하지 못했습니다. 내가 아직도 더 많은 것을 읽어야하는 것은 나에게 새로운 개념이다. 자세한 답변을 주셔서 감사합니다. – mpen

관련 문제