2010-01-20 5 views
4

저는 타입 캐스팅이 이상하다고 생각합니다.C# 타입 캐스팅 기이 한 타입 - 일반적인 타입의 인터페이스

이 (classSet)을 해봐요 다네
interface IMyClass { } 

class MyClass: IMyClass { } 

class Main 
{ 
    void DoSomething(ICollection<IMyClass> theParameter) { } 

    HashSet<MyClass> FillMyClassSet() 
    { 
    //Do stuff 
    } 

    void Main() 
    { 
    HashSet<MyClass> classSet = FillMyClassSet(); 
    DoSomething(classSet); 
    } 
} 

, 컴파일러는 <IMyClass>을 ICollection이하는 HashSet의 < MyClass에 > 캐스팅 할 수없는 불평 : 나는 다음과 같은 코드가 있습니다. 왜 그런가요? HashSet은 ICollection을 구현하고 MyClass는 IMyClass를 구현하므로 왜 캐스트가 유효하지 않습니까?

덧붙여 말하면, 이것은 조금 힘들다고 생각합니다.

void Main() 
{ 
    HashSet<MyClass> classSet = FillMyClassSet(); 
    HashSet<IMyClass> interfaceSet = new HashSet<IMyClass>(); 
    foreach(IMyClass item in classSet) 
    { 
    interfaceSet.Add(item); 
    } 
    DoSomething(interfaceSet); 
} 

나에게이 작품은 사실 더 이상 불가사의하게 만들 수 없다.

+0

@ Mehrdad 's가 이유에 대한 답을 얻었습니다. 하지만'foreach' 대신'FillMyClassSet()'의 리턴 타입을'HashSet '으로 바꿀 수 있습니까? – JMD

답변

8

MyClass 인 모든 인스턴스가 IMyClass 인 경우 자동으로 HashSet<MyClass> 인 모든 인스턴스가 HashSet<IMyClass>임을 나타내지 않으므로 작동하지 않습니다. 이 일 경우에, 당신은 할 수 : C#을 (< = 3.0) 제네릭는 불변이기 때문에

ICollection<IMyClass> h = new HashSet<MyClass>(); 
h.Add(new OtherClassThatImplementsIMyClass()); // BOOM! 

기술적으로 작동하지 않습니다. C# 4.0에서는이 경우에도 도움이되지 않는 안전한 공분산을 도입했습니다. 그러나 인터페이스가 입력에서만 또는 출력 위치에서만 유형 매개 변수를 사용할 때 도움이됩니다. 예를 들어 HashSet<MyClass>IEnumerable<IMyClass>으로 전달할 수 있습니다. 그런데

, 그들은 수동으로 채우는 것보다 쉽게 ​​해결 방법은 다른 HashSet 같은 :

var newSet = new HashSet<IMyClass>(originalSet); 

또는 당신이 IEnumerable<IMyClass>에 세트를 캐스팅하려는 경우가 Cast 방법을 사용할 수 있습니다 :

IEnumerable<IMyClass> sequence = set.Cast<IMyClass>(set); 
+2

+1 빙고 ..... 15 – JMD

+0

내가 더 많은 시간을 주었 더라면 나는 그것을 결국 깨달았어야했다. 4.0 정보는 흥미 롭습니다. 그래서 DoSomething (IEnumerable theParameter)으로 변경할 수 있다면 4.0에서 캐스트가 작동할까요? 즉, 실제로 IEnumerable을 사용해야한다고 가정합니다. – JamesH

+0

예; 4.0에서 작동하고 안전 할 것입니다. 3.0에서는'Cast' 메서드를 사용해야합니다 (안전하다고해도 컴파일러와 런타임에서는 이에 대해 전혀 알지 못합니다). –

2

그런 캐스트는 실제로 안전하지 않습니다.

이 코드를 고려

class MyOtherClass: IMyClass { } 

void DoSomething(ICollection<IMyClass> theParameter) { theParameter.Add(new MyOtherClass(); } 

ICollection<MyClass> myClassSet = ...; 
DoSomething(classSet); //Oops - myClassSet now has a MyOtherClass 

당신이 공분산라고 요구하고; C# 4에서 IEnumerable<T> (읽기 전용)으로 사용할 수 있습니다.