List에서 캐스트하기위한 더 짧은 구문 목록으로?
다음과 같이 한 번에 하나씩 한 유형에서 다른 유형으로 항목 목록을 캐스팅 할 수 있다는 것을 알고 있습니다 (캐스팅을 수행하는 공개 정적 명시 적 연산자 메소드가있는 경우).
List<Y> ListOfY = new List<Y>();
foreach(X x in ListOfX)
ListOfY.Add((Y)x);
그러나 한 번에 전체 목록을 전송할 수 없습니까? 예를 들어
ListOfY = (List<Y>)ListOfX;
경우 X
정말 캐스팅 할 수 있습니다 Y
당신은 사용할 수 있어야합니다
List<Y> listOfY = listOfX.Cast<Y>().ToList();
알아 두어야 할 사항 (해설자에게 H / T!)
using System.Linq;
이 확장 방법을 얻으려면 포함시켜야합니다- 그러면 목록 자체가 아닌 목록의 각 항목이 캐스팅됩니다. 을 (를)
List<Y>
호출하면 새로운 내용이 생성됩니다ToList()
. - 이 방법은 맞춤 전환 연산자를 지원하지 않습니다. ( http://stackoverflow.com/questions/14523530/why-does-the-linq-cast-helper-not-work-with-the-implicit-cast-operator 참조 )
- 이 메소드는 명시 적 연산자 메소드 (framework 4.0)가있는 오브젝트에는 작동하지 않습니다.
직접 캐스팅 var ListOfY = (List<Y>)ListOfX
이 필요하기 때문에 가능하지 않다 공동 / contravariance 의 List<T>
유형을, 그 다만 모든 경우에 보장 할 수 없습니다. 이 캐스팅 문제에 대한 솔루션을 보려면 계속 읽으십시오.
다음과 같은 코드를 작성할 수있는 것이 정상인 것 같습니다.
List<Animal> animals = (List<Animal>) mammalList;
우리는 모든 포유류가 동물이 될 것이라고 보장 할 수 있기 때문에 이것은 분명히 실수입니다.
List<Mammal> mammals = (List<Mammal>) animalList;
모든 동물이 포유류가 아니기 때문입니다.
그러나 C # 3 이상을 사용하면
IEnumerable<Animal> animals = mammalList.Cast<Animal>();
캐스팅이 약간 쉬워집니다. 이것은 명시 적으로 캐스트를 사용 Mammal
하여 목록의 각 을 으로 캐스트하고 캐스트 Animal
가 실패하면 실패 하므로 하나씩 추가 코드와 구문 적으로 동일합니다 .
캐스팅 / 변환 프로세스에 대한 제어를 강화하려는 경우 제공된 표현식을 사용하여 항목을 변환 할 수 ConvertAll
있는 List<T>
클래스 의 메소드를 사용할 수 있습니다. 이 List
대신 에을 반환하는 이점이 IEnumerable
있으므로 .ToList()
필요 하지 않습니다.
List<object> o = new List<object>();
o.Add("one");
o.Add("two");
o.Add(3);
IEnumerable<string> s1 = o.Cast<string>(); //fails on the 3rd item
List<string> s2 = o.ConvertAll(x => x.ToString()); //succeeds
Sweko의 요점을 추가하려면 :
캐스트가 필요한 이유
var listOfX = new List<X>();
ListOf<Y> ys = (List<Y>)listOfX; // Compile error: Cannot implicitly cast X to Y
가능하지 않은이 때문입니다 List<T>
입니다 유형 T에서 일정 때문에 그것은 여부를 중요하지 않습니다 X
에서 파생 Y
) -이 때문에되어 List<T>
다음과 같이 정의된다
public class List<T> : IList<T>, ICollection<T>, IEnumerable<T> ... // Other interfaces
(이 선언에서 T
여기 에 입력 하면 추가 분산 수정자가 없습니다.)
However, if mutable collections are not required in your design, an upcast on many of the immutable collections, is possible, e.g. provided that Giraffe
derives from Animal
:
IEnumerable<Animal> animals = giraffes;
This is because IEnumerable<T>
supports covariance in T
- this makes sense given that IEnumerable
implies that the collection cannot be changed, since it has no support for methods to Add or Remove elements from the collection. Note the out
keyword in the declaration of IEnumerable<T>
:
public interface IEnumerable<out T> : IEnumerable
(Here's further explanation for the reason why mutable collections like List
cannot support covariance
, whereas immutable iterators and collections can.)
Casting with .Cast<T>()
As others have mentioned, .Cast<T>()
can be applied to a collection to project a new collection of elements casted to T, however doing so will throw an InvalidCastException
if the cast on one or more elements is not possible (which would be the same behaviour as doing the explicit cast in the OP's foreach
loop).
Filtering and Casting with OfType<T>()
If the input list contains elements of different, incompatable types, the potential InvalidCastException
can be avoided by using .OfType<T>()
instead of .Cast<T>()
. (.OfType<>()
checks to see whether an element can be converted to the target type, before attempting the conversion, and filters out incompatable types.)
foreach
Also note that if the OP had written this instead: (note the explicit Y y
in the foreach
)
List<Y> ListOfY = new List<Y>();
foreach(Y y in ListOfX)
{
ListOfY.Add(y);
}
that the casting will also be attempted. However, if no cast is possible, an InvalidCastException
will result.
Examples
For example, given the simple (C#6) class hierarchy:
public abstract class Animal
{
public string Name { get; }
protected Animal(string name) { Name = name; }
}
public class Elephant : Animal
{
public Elephant(string name) : base(name){}
}
public class Zebra : Animal
{
public Zebra(string name) : base(name) { }
}
When working with a collection of mixed types:
var mixedAnimals = new Animal[]
{
new Zebra("Zed"),
new Elephant("Ellie")
};
foreach(Animal animal in mixedAnimals)
{
// Fails for Zed - `InvalidCastException - cannot cast from Zebra to Elephant`
castedAnimals.Add((Elephant)animal);
}
var castedAnimals = mixedAnimals.Cast<Elephant>()
// Also fails for Zed with `InvalidCastException
.ToList();
Whereas:
var castedAnimals = mixedAnimals.OfType<Elephant>()
.ToList();
// Ellie
filters out only the Elephants - i.e. Zebras are eliminated.
Re: Implicit cast operators
Without dynamic, user defined conversion operators are only used at compile-time*, so even if a conversion operator between say Zebra and Elephant was made available, the above run time behaviour of the approaches to conversion wouldn't change.
If we add a conversion operator to convert a Zebra to an Elephant:
public class Zebra : Animal
{
public Zebra(string name) : base(name) { }
public static implicit operator Elephant(Zebra z)
{
return new Elephant(z.Name);
}
}
Instead, given the above conversion operator, the compiler will be able to change the type of the below array from Animal[]
to Elephant[]
, given that the Zebras can be now converted to a homogeneous collection of Elephants:
var compilerInferredAnimals = new []
{
new Zebra("Zed"),
new Elephant("Ellie")
};
Using Implicit Conversion Operators at run time
*As mentioned by Eric, the conversion operator can however be accessed at run time by resorting to dynamic
:
var mixedAnimals = new Animal[] // i.e. Polymorphic collection
{
new Zebra("Zed"),
new Elephant("Ellie")
};
foreach (dynamic animal in mixedAnimals)
{
castedAnimals.Add(animal);
}
// Returns Zed, Ellie
You can use List<Y>.ConvertAll<T>([Converter from Y to T]);
This is not quite the answer to this question, but it may be useful for some: as @SWeko said, thanks to covariance and contravariance, List<X>
can not be cast in List<Y>
, but List<X>
can be cast into IEnumerable<Y>
, and even with implicit cast.
Example:
List<Y> ListOfY = new List<Y>();
List<X> ListOfX = (List<X>)ListOfY; // Compile error
but
List<Y> ListOfY = new List<Y>();
IEnumerable<X> EnumerableOfX = ListOfY; // No issue
The big advantage is that it does not create a new list in memory.
참고URL : https://stackoverflow.com/questions/5115275/shorter-syntax-for-casting-from-a-listx-to-a-listy
'Programing' 카테고리의 다른 글
JavaScript를 사용하여 쉼표로 구분 된 문자열을 분할하는 방법은 무엇입니까? (0) | 2020.04.27 |
---|---|
C ++ 함수에서 여러 값 반환 (0) | 2020.04.27 |
언제 Debug.Assert ()를 사용해야합니까? (0) | 2020.04.27 |
파일을 어떻게 이동합니까? (0) | 2020.04.27 |
jQuery-선택한 옵션에서 사용자 정의 속성 가져 오기 (0) | 2020.04.27 |