List <T>를 List <Interface>로 캐스팅


답변:


250

캐스팅 할 수 없습니다 (참조 ID 유지)-안전하지 않습니다. 예를 들면 :

public interface IFruit {}

public class Apple : IFruit {}
public class Banana : IFruit {}

...

List<Apple> apples = new List<Apple>();
List<IFruit> fruit = apples; // Fortunately not allowed
fruit.Add(new Banana());

// Eek - it's a banana!
Apple apple = apples[0];

이제 공분산으로 인해 .NET 4 / C # 4에서 a List<Apple>로 변환 할 수 IEnumerable<IFruit>있지만, 원하는 경우 목록 List<IFruit>을 만들어야 합니다. 예를 들면 :

// In .NET 4, using the covariance of IEnumerable<T>
List<IFruit> fruit = apples.ToList<IFruit>();

// In .NET 3.5
List<IFruit> fruit = apples.Cast<IFruit>().ToList();

그러나 이것은 원래 목록을 캐스팅하는 것과 동일 하지 않습니다 . 이제 두 개의 개별 목록 이 있기 때문 입니다. 이것은 안전하지만 한 목록에 대한 변경 사항이 다른 목록에 표시되지 않음 을 이해해야 합니다. ( 물론 목록이 참조 하는 개체 에 대한 수정 사항 이 표시됩니다.)


6
마치 '아직 건물 안에'있는 것처럼!
Andras Zoltan

1
공분산을 수행하는 것과 새로운 List <IFruit> ()를 수행하는 것의 차이점은 무엇입니까? 그런 다음 원래 목록에 대한 foreach 및 각 항목을 IFruit 목록에 추가 하시겠습니까? foreach 방식으로 ... 객체 참조는 동일합니다. 맞습니까? 그러니 ... 그게 사실이라면, 전체 목록을 직접 캐스팅 할 수 없다는 것은 개인적으로 이해가되지 않습니다. ?
Robert Noack

3
@RobertNoack : "객체 참조"란 무엇을 의미합니까? 각 요소 의 개체 참조 는 동일하지만 목록 참조 자체를 캐스팅하는 것과는 다릅니다. List<IFruit>실제로 .NET Framework에 대한 참조 인 컴파일 타임 유형의 참조가 있도록 참조를 캐스팅 할 수 있다고 가정합니다 List<Apple>. Banana그것에 대한 참조를 추가하면 어떤 일이 발생할 것으로 예상 List<IFruit>합니까?
Jon Skeet 2014

1
오. 읽는 법을 배워야 할 것 같아요. 나는 원래의 대답이 목록의 객체가 딥 복사되고 다시 만들어 질 것이라고 생각했는데 이는 나에게 의미가 없습니다. 그러나 동일한 객체로 새 목록 만 생성되는 부분을 분명히 놓쳤습니다.
Robert Noack 2014

2
@ TrươngQuốcKhánh : 나는 아무 생각이 무엇을 어떤 처럼 코드 외모의, 또는 당신은이 있는지 여부 using에 대한 지침 System.Linq, 또는 당신이 내가 당신이 나를 도울 수있을 것으로 기대 방법이 아니에요, 그것을 호출 위해 노력하고 있습니다. 더 많은 조사를 할 것을 제안하고 여전히 막혀 있다면 최소한의 재현 가능한 예를 사용하여 질문하십시오 .
존 소총

6

캐스트 반복기 및 .ToList () :

List<IDic> casted = input.Cast<IDic>().ToList() 트릭을 할 것입니다.

원래 저는 공분산이 효과가 있다고 말했지만 Jon이 올바르게 지적했듯이; 안돼!

그리고 원래 나도 멍청하게 ToList()전화를 끊었 어


Cast반환 IEnumerable<T>하지 않습니다 List<T>-및 아니오, 공분산 안전하지 않기 때문에이 변환을 허용 하지 않습니다 -내 대답을 참조하십시오.
Jon Skeet

"유형의 위임 유형은 변형 유형 매개 변수를 가질 수 있습니다 만 인터페이스": 당신이 링크 된 페이지에서
존 소총

@Jon- ToList()귀하의 의견을 읽기 전에가 누락 되었음을 깨달았습니다 . 그러나 물론 공분산은 작동하지 않습니다! 도!
Andras Zoltan 2012 년

권리. 공분산은 Cast.NET 4에서 형식 인수를 지정하는 한 .NET 4 에서 호출이 필요하지 않음을 의미하므로 여전히 도움이 될 수 있습니다 ToList.
Jon Skeet

5

나도이 문제를했고 존 소총의 답변을 읽은 후 내가 사용하는 내 코드를 수정 List<T>사용 IEnumerable<T>. 이것이 OP의 원래 질문 인 How can I cast List<Client>to에List<IDic> 대한 답변은 아니지만 그렇게 할 필요가 없으므로이 문제를 겪는 다른 사람들에게 도움이 될 수 있습니다. 물론 이것은 사용이 필요한 코드를 가정합니다.List<IDic> 귀하의 통제하에 .

예 :

public void ProcessIDic(IEnumerable<IDic> sequence)
{
   // Implementation
}

대신에:

public void ProcessIDic(List<IDic> list)
{
   // Implementation
}

3

LINQ를 사용할 수 있다면 이렇게 할 수 있습니다.

List<Client> clientList = new List<Client>();
List<IDic> list = clientList.Select(c => (IDic)c).ToList();

3
List<Client> listOfA = new List<Client>();
List<IDic> list = listOfA.Cast<IDic>().ToList();

0

새로 만들고 List<IDic>모든 요소를 ​​전송 해야만 가능 합니다.


일반적인 의미가 다른 모든 답변과 동일하기 때문에 반대 투표를 한 이유는 무엇입니까?
Piotr Auguscik

내 추측은 당신이 새 목록을 만드는 것이 가능하다고 말했기 때문에 당신이 반대표를 받았을 것입니다. 그러나 다른 사람들은 반대로 게시했습니다. 그래도 내
반대표는

글쎄 그들은 새로운 목록을 만들지 만 사실을 변경하지 않는 new 연산자를 사용하지 않습니다.
Piotr Auguscik

0

.Net 3.5에서는 다음을 수행 할 수 있습니다.

List<ISomeInterface> interfaceList = new List<ISomeInterface>(list.Cast<ISomeInterface>());

이 경우 List 생성자는 IEnumerable을 사용합니다.
목록 은 IEnumerable로만 변환 할 수 있습니다. myObj 를 ISomeInterface로 변환 할 수 있지만 IEnumerable 유형은 IEnumerable로 변환 할 수 없습니다.


문제는 이것이 목록의 복사본을 만드는 것입니다. 대부분의 경우 원래 목록에서 작업을 수행하려고합니다
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.