2009-03-04 6 views
6

최근에 나는 C#에서 매우 놀라운 동작을 발견했습니다. 나는 IEnumerable<Object>을 매개 변수로 사용하는 메서드를 사용하고 있었고 IEnumerable<string>을 전달했지만 불가능합니다. C#에서는이 모든 것이 왜 가능하지 않은 것보다 Object에 업 캐스트 될 수 있습니까? 완전히 혼란 스럽습니다. 누군가이 문제에 대해 저를 정리해주십시오.IEnumerable <Object>에서 IEnumerable로 캐스팅 <string>

+0

어떻게 가능하지 않습니까? 그것은 ArgumentException을 던지고 있습니까? 게다가, Object로 선언 할 경우 일반 IEnumerable 사용의 요지는 무엇입니까? –

+0

컴파일 오류 –

+0

다음과 동일합니다 : http://stackoverflow.com/questions/6557/in-c-why-cant-a-liststring-object-be-stored-in-a-listobject-variable –

답변

11

이 기술 용어는 제네릭이 C# 3.0 이하에서는 불변하다는 것입니다. C# 4.0 이후부터 캐스트가 작동합니다.

불변량이란 두 가지 제네릭 유형이 각각 매개 변수과 관련되어 있으므로 (즉, 서로의 하위 또는 상위 유형 임) 관계가 없다는 것을 의미합니다.

예를 들어 문자열이 객체의 하위 유형이기 때문에 IEnumerable<object>IEnumerable<string> 사이에는 타이핑 관계가 없습니다. 그들은 문자열과 int 같은 두 개의 완전히 관련없는 유형으로 간주됩니다. (여전히 둘 다 객체의 하위 유형이지만 모두 같습니다.)

실행 한이 문제에 대한 몇 가지 해결 방법과 예외가 있습니다.

먼저 각 문자열을 객체에 캐스팅 할 수 있습니다. .NET 3.0을 사용하는 경우 Cast<T>() 확장 메소드를 사용하여이를 수행 할 수 있습니다. 그렇지 않으면 foreach를 사용하여 결과를 원하는 정적 유형의 새 변수에 넣을 수 있습니다.

둘째, 배열은 참조 유형에 대한 예외입니다. 즉, [] 유형을 객체 [] 유형을 인식하는 메소드로 전달하면 유형이 작동합니다. 당신이 다른 유형에 전달하려면

+1

그냥 이 오래된 대답을 업데이트하면 공분산과 반공립이 C#에서 지원되며 이제는 유효한 캐스트가되었습니다. –

0

그런 다음 당신이 무슨 타입인지 찾기 위해 T를 조회 할 수 있습니다,

IEnumerable<T> 

를 사용한다.

0

이것에 대해 생각하는 좋은 방법은 "이 일을 할 수 있다면 어떻게 될까요?"라고 자문하는 것입니다. 다음 예를 참조하십시오.

IEnumerable<String> strings=...; 
IEnumerable<Object> objects = strings; // assume this were legal 

objects.Add(new Integer(5)); // what the... 

방금 ​​문자열 목록에 정수를 추가했습니다. 컴파일러는 형식 안전성을 유지하기 위해이 작업을 수행합니다.

+0

IEnumerable 에는 Add 메서드가 없습니다 ... 그리고 C# 4.0에서는 실제로 선언이 IEnumerable 으로 변경되어 (반대로) 반항적 이도록 허용하므로이 캐스트를 수행 할 수 있습니다. –

+0

List와 같은 Add 메소드가있는 제네릭 클래스를 대체하면 –

+0

-1 : IEnumerable '이 .NET 4에서 'IEnumerable '이됩니다. 특히 인수가 컨테이너에 대해 의미가 있지만 열거 형에 대해서는 *가 아니기 때문에 가능합니다. –

3

IEnumerable<object>을 필요로하는 기능 IEnumerable<string>를 전달하는 가장 쉬운 방법은 다음과 같이 변환 기능을 통해 : C# 4가 나올 때 공분산 및 contravariance을 지원하기 때문에

public IEnumerable<object> convert<T>(IEnumerable<T> enumerable) 
    { 
    foreach (T o in enumerable) 
     yield return o; 
    } 

,이,이 켜지지되지 않습니다.

+2

정확하게 캐스트 <>가 다음과 같습니다. –

+0

감사! 나는 이미이 제안에 대한 대답을 upvoted. –

8

다른 사람들이 지적한 것처럼 제네릭 유형은 변하지 않습니다. IEnumerable<T>은 동일 변종이지만 C#은 현재 변종 지정을 지원하지 않습니다. C# 4.0은 향후에 지원 될 수 있도록 변형을 지원할 것으로 예상됩니다.

이제이 문제를 해결하려면 LINQ 확장 방법 Cast<object>()을 사용할 수 있습니다. Foo이라는 메서드가 있다고 가정하면 IEnumerable<object>>이 필요합니다.이렇게 부를 수 있습니다.

Foo(stringEnumerable.Cast<object>()); 
관련 문제