2014-08-29 4 views
5

이유는 Enumerator 컬렉션 수정할 수 없습니다 때문이다 : 우리가 List<object>과 같은 일을하려고하면 IEnumerable<object> 대신,왜 ReadOnlyCollection에는 공분산이 허용되지 않습니까? 이 코드가 작동

var roList = new List<string>() { "One", "Two", "Three" }; 
IEnumerable<object> objEnum = roList; 

을, 우리는 컴파일러 오류 텔링을 얻을 것 암시 적으로 유형 List<string>List<object>으로 변환 할 수 없습니다. 좋아, 저것은 이해가된다. 그리고 나의 의견으로는, 배열로부터 배웠던 교훈으로서 마이크로 소프트에 의한 좋은 결정이었다.

그러나 내가 알 수없는 것은 세계에서이 강경론 규칙이 ReadOnlyCollection과 같은 것에 적용되는 이유는 무엇입니까? ReadOnlyCollection의 요소를 수정할 수 없으므로 Microsoft에서 안전을 고려했을 때 읽기 전용 인 것과 함께 공분산을 사용하지 못하게했을 수 있습니다. 포인터를 통해 Microsoft가 고려하려고했던 컬렉션 유형을 수정할 수있는 방법이 있습니까?

+1

"배열에서 배운 교훈": 배열 공분산에 대해, 이것은 실제로 자바가 허용했기 때문에 의식적인 디자인 결정이었습니다. 그것은 꽤 나쁜 생각으로 밝혀졌습니다 ... http://blogs.msdn.com/b/ericlippert/archive/2007/10/17/covariance-and-contravariance-in-c-part-two-array- covariance.aspx –

+0

@ThomasLevesque 좋은 읽을 거리, 감사합니다. –

답변

7

분산 및 반공립은 클래스가 아닌 인터페이스 및 델리게이트에서만 작동합니다.

그러나, 당신은 할 수있다 (.NET 4.5을 사용하여) :

ReadOnlyCollection<string> roList = ... 
IReadOnlyCollection<object> objects = roList; 


하는 분산이 클래스에서 허용되지 않는 이유에 대한 질문에 대답하기 위해 (IReadOnlyCollection<T>는 공변이기 때문이다) 여기 그의 책 C# in Depth (제 2 판, §13.3.5, 394 페이지)의 Jon Skeet의 설명이 있습니다.

전용 인터페이스 및 대리자 변형 유형 파라미터를 가질 수 CLASSES IN TYPE 파라미터는

NO VARIANCE 없다. 심지어 입력에 대해서만 형식 매개 변수를 사용하는 클래스가 있거나 이 출력용으로 만 사용하는 클래스 인 경우 in 또는 out 수정자를 지정할 수 없습니다. 예를 들어 Comparer<T> 인 경우 IComparer<T>의 일반적인 구현은 변하지 않습니다. Comparer<IShape>에서 Comparer<Circle>으로 변환되지 않습니다.

이 발생했을 수있는 구현상의 어려움 외에도 개념적으로는 일정한 의미를 지닌다고 할 수 있습니다. 인터페이스는 특정 관점의 객체를 보는 방법을 나타내지 만 클래스는 객체의 실제 유형에 뿌리를두고 있습니다. 이 인수는 상속에 의해 객체를 클래스의 인스턴스로 처리하게하여 다소 약화됩니다. 상속 계층 구조입니다. 어느 쪽이든, CLR은 을 허용하지 않습니다.

+0

네 말이 맞아.나는 그것을 테스트했고 읽기 전용 인터페이스'IReadOnlyCollection '와'IReadOnlyList '와 함께 작동합니다. 클래스와 함께 작동하지 않는 이유는 무엇입니까? –

+0

@ B.K., 나도 모르겠지만, 내 추측에 따르면 일부 CLR 내부 구현 세부 사항과 관련이 있습니다 ... –

+0

아마도 인터페이스 지원을 구현하는 것이 더 쉽습니다. 하나의 구체적인 유형에서 기본 구체 유형으로 캐스트 할 때 기본 유형은 실제 상속에서만 정의되는 가상/대체/숨기기 시나리오에 따라 메소드 또는 기본 유형을 호출할지 여부를 결정해야합니다. ReadOnlyCollection 은 ReadOnlycollection 에서 상속받지 않으므로 어떤 일이 발생하는지 정의하기가 어렵습니다. 인터페이스는 항상 구체적인 유형으로 호출을 전달하며 기본 또는 파생 클래스가 호출되는지에 대한 모호성이 없습니다. 그것은 공변 인터페이스에 액세스하는 것이 무엇을 의미하는지 훨씬 명확합니다. IMO – AaronLS