[c#] C #에서 List <string> 개체를 List <object> 변수에 저장할 수없는 이유

List 개체는 C #의 List 변수에 저장할 수 없으며 명시 적으로 캐스팅 할 수도 없습니다.

List<string> sl = new List<string>();
List<object> ol;
ol = sl;

암시 적으로 유형 System.Collections.Generic.List<string>을 다음으로 변환 할 수 없음System.Collections.Generic.List<object>

그리고…

List<string> sl = new List<string>();
List<object> ol;
ol = (List<object>)sl;

유형 System.Collections.Generic.List<string>을 다음으로 변환 할 수 없음System.Collections.Generic.List<object>

물론 문자열 목록에서 모든 것을 꺼내서 한 번에 하나씩 다시 넣는 방식으로 할 수 있지만 다소 복잡한 솔루션입니다.



답변

이런 식으로 생각해보십시오. 그런 캐스트를 한 다음 Foo 유형의 객체를 목록에 추가하면 문자열 목록이 더 이상 일관되지 않습니다. 첫 번째 참조를 반복하면 Foo 인스턴스에 도달하면 Foo를 문자열로 변환 할 수 없기 때문에 클래스 캐스트 예외가 발생합니다!

참고로 리버스 캐스트를 할 수 있는지 여부가 더 중요하다고 생각합니다.

List<object> ol = new List<object>();
List<string> sl;
sl = (List<string>)ol;

한동안 C #을 사용하지 않았기 때문에 그것이 합법적인지 모르겠지만 그런 종류의 캐스트가 실제로 (잠재적으로) 유용합니다. 이 경우 더 일반적인 클래스 (객체)에서 일반 클래스 (문자열)에서 확장되는 더 구체적인 클래스 (문자열)로 이동합니다. 이런 식으로 문자열 목록에 추가하는 경우 개체 목록을 위반하지 않습니다.

누구든지 그러한 캐스트가 C #에서 합법적인지 알고 있거나 테스트 할 수 있습니까?


답변

.NET 3.5를 사용하는 경우 Enumerable.Cast 메서드를 살펴보십시오. 확장 메서드이므로 목록에서 직접 호출 할 수 있습니다.

List<string> sl = new List<string>();
IEnumerable<object> ol;
ol = sl.Cast<object>();

정확히 당신이 요청한 것은 아니지만 트릭을해야합니다.

편집 : Zooba에서 언급했듯이 ol.ToList ()를 호출하여 목록을 가져올 수 있습니다.


답변

유형 매개 변수가 다른 일반 유형 간에는 캐스트 할 수 없습니다. 특수화 된 제네릭 유형은 동일한 상속 트리의 일부를 형성하지 않으므로 관련되지 않은 유형도 마찬가지입니다.

NET 3.5 이전을 수행하려면 :

List<string> sl = new List<string>();
// Add strings to sl

List<object> ol = new List<object>();

foreach(string s in sl)
{
    ol.Add((object)s);  // The cast is performed implicitly even if omitted
}

Linq 사용 :

var sl = new List<string>();
// Add strings to sl

var ol = new List<object>(sl.Cast<object>());

// OR
var ol = sl.Cast<object>().ToList();

// OR (note that the cast to object here is required)
var ol = sl.Select(s => (object)s).ToList();


답변

그 이유는 같은 일반 클래스 List<>가 대부분의 경우 외부에서 일반 클래스로 취급되기 때문입니다. 예를 들어 List<string>()컴파일러가 ListString()(문자열 포함) 이라고 말할 때 . [기술 전문가 : 이건 무슨 일이 벌어지고 있는지 매우 평이한 영어 버전입니다.]

결과적으로 컴파일러는 내부 컬렉션의 항목을 캐스팅하여 ListString을 ListObject로 변환 할만큼 똑똑 할 수 없습니다.

그렇기 때문에 Convert ()와 같은 IEnumerable의 확장 메서드가있어 컬렉션 내에 저장된 항목에 대한 변환을 쉽게 제공 할 수 있습니다.이 메서드는 서로 캐스팅하는 것처럼 간단 할 수 있습니다.


답변

이것은 공분산과 많은 관련이 있습니다. 예를 들어 제네릭 유형은 매개 변수로 간주되며 매개 변수가 더 구체적인 유형으로 제대로 해석되지 않으면 작업이 실패합니다. 이러한 의미는 객체와 같은보다 일반적인 유형으로 형변환 할 수 없다는 것입니다. Rex가 말했듯이 List 객체는 각 객체를 변환하지 않습니다.

대신 ff 코드를 시도해 볼 수 있습니다.

List<string> sl = new List<string>();
//populate sl
List<object> ol = new List<object>(sl);

또는:

List<object> ol = new List<object>();
ol.AddRange(sl);

ol은 (이론적으로) sl의 모든 내용을 문제없이 복사합니다.


답변

예, .NET 3.5에서 다음을 수행 할 수 있습니다.

List<string> sl = new List<string>();
List<object> ol = sl.Cast<object>().ToList();


답변

Mike-C #에서도 반공 변성이 허용되지 않는다고 생각합니다.

자세한 내용 은 CLR의 일반 형식 매개 변수 변형을 참조하세요 .