C#에서 List<string> 개체를 List<object> 변수에 저장할 수 없는 이유는 무엇입니까?

StackOverflow https://stackoverflow.com/questions/6557

문제

C#에서는 List 개체를 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에서 직접 호출할 수 있는 확장 메서드입니다.

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의 일반 유형 매개변수 변화 더 많은 정보를 원하시면

내 생각엔 이(반공변성)이 실제로 C# 4.0에서 지원될 것이라고 생각합니다.http://blogs.msdn.com/charlie/archive/2008/10/27/linq-farm-covariance-and-contravariance-in-visual-studio-2010.aspx

이는 실제로 "ol" 목록 변형에 이상한 "객체"를 넣지 않으려는 것입니다(예: List<object> 허용하는 것 같습니다) - 그러면 코드가 충돌할 것이기 때문입니다(목록이 실제로 List<string> 문자열 유형 객체만 허용됩니다).그렇기 때문에 변수를 보다 일반적인 사양으로 캐스팅할 수 없습니다.

Java에서는 그 반대입니다. 제네릭이 없고 대신 모든 것이 런타임 시 객체 목록이며 실제로는 엄격하게 유형이 지정된 목록에 이상한 객체를 채울 수 있습니다.Java 문제에 대한 더 폭넓은 논의를 보려면 "Reified generics"를 검색하세요.

제네릭에 대한 이러한 공분산은 지원되지 않지만 실제로 배열을 사용하여 이를 수행할 수 있습니다.

object[] a = new string[] {"spam", "eggs"};

C#은 런타임 검사를 수행하여 사용자가 int ~ 안으로 a.

다음은 내용이 암시적으로 캐스팅될 수 있는 IList에 대한 또 다른 .NET 3.5 이전 솔루션입니다.

public IList<B> ConvertIList<D, B>(IList<D> list) where D : B
{
    List<B> newList = new List<B>();

    foreach (D item in list)
    {
        newList.Add(item);
    }

    return newList;
}

(Zoba의 예를 기반으로 함)

나는 다음을 가지고 있습니다 :

private List<Leerling> Leerlingen = new List<Leerling>();

그리고 저는 그 공간을 수집된 데이터로 채울 예정이었습니다. List<object>마침내 나에게 도움이 된 것은 다음과 같습니다.

Leerlingen = (List<Leerling>)_DeserialiseerLeerlingen._TeSerialiserenObjecten.Cast<Leerling>();

.Cast 당신이 얻고 싶은 유형에 맞춰 IEnumerable 해당 유형에서 타입캐스트한 다음 IEnemuerable ~로 List<> 당신이 원하는.

음, 이전 댓글 덕분에 이를 찾는 두 가지 방법을 찾았습니다.첫 번째는 요소의 문자열 목록을 가져온 다음 이를 IEnumerable 개체 목록으로 캐스팅하는 것입니다.

IEnumerable<object> ob;
List<string> st = new List<string>();
ob = st.Cast<object>();

두 번째는 IEnumerable 객체 유형을 피하는 것입니다. 문자열을 객체 유형으로 캐스팅한 다음 같은 문장에서 "toList()" 함수를 사용하면 됩니다.

List<string> st = new List<string>();
List<object> ob = st.Cast<object>().ToList();

나는 두 번째 방법을 더 좋아한다.이게 도움이 되길 바란다.

List<string> sl = new List<string>();
List<object> ol;
ol = new List<object>(sl);
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top