C # 분산 문제 : 목록 할당 목록으로
다음 예제를 살펴보십시오 (부분적으로 MSDN Blog 에서 가져옴 ).
class Animal { }
class Giraffe : Animal { }
static void Main(string[] args)
{
// Array assignment works, but...
Animal[] animals = new Giraffe[10];
// implicit...
List<Animal> animalsList = new List<Giraffe>();
// ...and explicit casting fails
List<Animal> animalsList2 = (List<Animal>) new List<Giraffe>();
}
공분산 문제입니까? 이것은 향후 C # 릴리스에서 지원 될 예정이며 .NET 2.0 만 사용하는 현명한 해결 방법이 있습니까?
이것은 확실히 C # 4에서 지원되지 않을 것입니다. 근본적인 문제가 있습니다.
List<Giraffe> giraffes = new List<Giraffe>();
giraffes.Add(new Giraffe());
List<Animal> animals = giraffes;
animals.Add(new Lion()); // Aargh!
기린을 안전하게 지키십시오 : 안전하지 않은 변수에 대해 거절하십시오.
배열 버전은 실행 시간 검사와 함께 배열 이 참조 유형 분산을 지원 하기 때문에 작동합니다 . 제네릭의 요점은 컴파일 타임 유형 안전성 을 제공하는 것 입니다.
C # 4에서는 안전한 제네릭 분산을 지원 하지만 인터페이스와 대리자에 대해서만 지원합니다 . 따라서 다음을 수행 할 수 있습니다.
Func<string> stringFactory = () => "always return this string";
Func<object> objectFactory = stringFactory; // Safe, allowed in C# 4
Func<out T>
인 공변 에 T
때문 T
만 출력 위치에 사용된다. 입력 위치에서만 사용 되기 때문에 Action<in T>
반변적인 것과 비교하여 안전합니다.T
T
Action<object> objectAction = x => Console.WriteLine(x.GetHashCode());
Action<string> stringAction = objectAction; // Safe, allowed in C# 4
IEnumerable<out T>
다른 사람들이 지적한 바와 같이 C # 4에서 올바르게 만듭니다.
IEnumerable<Animal> animals = new List<Giraffe>();
// Can't add a Lion to animals, as `IEnumerable<out T>` is a read-only interface.
C # 2의 상황에서이 문제를 해결하는 측면에서 하나의 목록 을 유지해야 합니까? 아니면 새 목록을 만드는 데 만족할까요? 그것이 받아 들여 진다면, List<T>.ConvertAll
당신의 친구입니다.
.NET 용 C # 4에서 작동 IEnumerable<T>
하므로 다음을 수행 할 수 있습니다.
IEnumerable<Animal> animals = new List<Giraffe>();
그러나 List<T>
공변 프로젝션이 아니므로 위와 같이 할 수 있으므로 목록을 할당 할 수 없습니다.
List<Animal> animals = new List<Giraffe>();
animals.Add(new Monkey());
분명히 유효하지 않습니다.
의 관점에서 볼 때 List<T>
운이 좋지 않은 것 같습니다. 그러나 .NET 4.0 / C # 4.0은 공변 / 반 변성 인터페이스에 대한 지원을 추가합니다. 특히 IEnumerable<T>
는 이제로 정의되어 IEnumerable<out T>
형식 매개 변수가 이제 공변 임을 의미합니다 .
이것은 C # 4.0에서 이와 같은 작업을 할 수 있음을 의미합니다.
// implicit casting
IEnumerable<Animal> animalsList = new List<Giraffe>();
// explicit casting
IEnumerable<Animal> animalsList2 = (IEnumerable<Animal>) new List<Giraffe>();
참고 : 배열 유형도 공변했습니다 (적어도 .NET 1.1 이후).
IList<T>
다른 유사한 제네릭 인터페이스 (또는 제네릭 클래스) 에 대해 분산 지원이 추가되지 않은 것은 부끄러운 일이지만, 적어도 우리는 뭔가를 가지고 있습니다.
Covariance/contravariance can't be supported on mutable collections as others have mentioned because it's impossible to guarantee type safety both ways at compile time; however, it is possible to do a quick one-way conversion in C# 3.5, if that is what you're looking for:
List<Giraffe> giraffes = new List<Giraffe>();
List<Animal> animals = giraffes.Cast<Animal>().ToList();
Of course it's not the same thing, it's not actually covariance - you're actually creating another list, but it is a "workaround" so to speak.
In .NET 2.0, you can take advantage of array covariance to simplify the code:
List<Giraffe> giraffes = new List<Giraffe>();
List<Animal> animals = new List<Animal>(giraffes.ToArray());
But be aware that you're actually creating two new collections here.
ReferenceURL : https://stackoverflow.com/questions/2033912/c-sharp-variance-problem-assigning-listderived-as-listbase
'program tip' 카테고리의 다른 글
`Object`는 JavaScript의 함수입니까? (0) | 2021.01.11 |
---|---|
DataContractSerializer에 의해 생성 된 XML 서식 (0) | 2021.01.11 |
Go에서 크기 조정이 가능한 배열을 구현하는 방법 (0) | 2021.01.10 |
Makefile 문제 : 디렉토리 트리에서 .c 파일을 스캔하는 현명한 방법 (0) | 2021.01.10 |
Visual Studio에서 코드 개요를 표시하는 방법은 무엇입니까? (0) | 2021.01.10 |