C # 컴파일러가 IEnumerable 간의 명시 적 캐스트를 허용하는 이유 그리고 TAlmostAnything?
다음 코드는 예상대로 컴파일러 오류를 제공합니다.
List<Banana> aBunchOfBananas = new List<Banana>();
Banana justOneBanana = (Banana)aBunchOfBananas;
그러나를 사용 IEnumerable<Banana>
하면 런타임 오류가 발생합니다.
IEnumerable<Banana> aBunchOfBananas = new List<Banana>();
Banana justOneBanana = (Banana)aBunchOfBananas;
C # 컴파일러가이를 허용하는 이유는 무엇입니까?
나는 그것이 아무리 어리석은 일이더라도 IEnumerable<T>
일부 구현 이 명시 적으로 캐스팅 될 수 있는 인터페이스 이기 때문이라고 생각합니다 Banana
.
반면에 컴파일러는 List<T>
명시 적으로 Banana
.
그건 그렇고, 좋은 예 선택!
명확히하기 위해 예제를 추가합니다. 아마도 우리는 항상 기껏 해야 하나를 포함해야하는 "열거 형"을 가질 것입니다 Banana
:
public class SingleItemList<T>:Banana, IEnumerable<T> where T:Banana {
public static explicit operator T(SingleItemList<T> enumerable) {
return enumerable.SingleOrDefault();
}
// Others omitted...
}
그런 다음 실제로 이렇게 할 수 있습니다 .
IEnumerable<Banana> aBunchOfBananas = new SingleItemList<Banana>();
Banana justOneBanana = (Banana)aBunchOfBananas;
다음을 작성하는 것과 동일하므로 컴파일러가 완벽하게 만족합니다.
Banana justOneBanana = aBunchOfBananas.SingleOrDefault();
당신이 말할 때 Y y = (Y)x;
이 캐스트가 컴파일러에 말한다 "어떤 신뢰 나에게, x
그것이로 주조 할 수 런타임에있다, Y
그래서, 알았지, 그것을?"
하지만 당신이 말할 때
List<Banana> aBunchOfBananas = new List<Banana>();
Banana justOneBanana = (Banana)aBunchOfBananas;
컴파일러는 이러한 각각의 구체적인 클래스 ( Banana
및 List<Banana>
) 에 대한 정의를 보고 static explicit operator Banana(List<Banana> bananas)
정의 된 것이 없음을 확인할 수 있습니다 (명시 적 캐스트는 캐스트되는 유형 또는 캐스트되는 유형에서 정의되어야합니다. 이것은 사양에서 가져온 것입니다.) , 섹션 17.9.4). 컴파일 타임에 당신이 말하는 것이 사실 일 수 없다는 것을 압니다. 그래서 거짓말을 그만두라고 소리 친다.
하지만 당신이 말할 때
IEnumerable<Banana> aBunchOfBananas = new List<Banana>();
Banana justOneBanana = (Banana)aBunchOfBananas;
이제 컴파일러는 알지 못합니다. aBunchOfBananas
런타임에 어떤 일이 발생 하든 그 구체적인 유형 X
이 정의되었을 수 있습니다 static explicit operator Banana(X bananas)
. 따라서 컴파일러는 요청한대로 사용자를 신뢰합니다.
컴파일러가 있기 때문에있을 수 있습니다 알고 그 Banana
연장하지 않는 List<T>
, 그러나 어떤 구현 일부 개체가 가능성이 있다고 IEnumerable<T>
도 연장 할 수 Banana
및 메이크업 유효한 캐스트 그.
언어 사양 (6.2.4)에 따르면 "명시 적 참조 변환은 다음과 같습니다. 모든 클래스 유형 S에서 인터페이스 유형 T로, S가 봉인되지 않고 S가 T를 구현하지 않는 경우 ... 명시 적 참조 변환은 다음과 같습니다. 올바른지 확인하기 위해 런타임 검사가 필요한 참조 유형 간의 변환 ... "
따라서 컴파일러는 컴파일 중에 인터페이스 구현을 확인하지 않습니다. 런타임에서 CLR을 수행합니다. 클래스 또는 부모 사이에서 실현을 찾으려고하는 메타 데이터를 확인합니다. 왜 이런 식으로 작동하는지 모르겠습니다. 아마도 시간이 많이 걸립니다. 따라서이 코드는 올바르게 컴파일됩니다.
public interface IInterface
{}
public class Banana
{
}
class Program
{
static void Main( string[] args )
{
Banana banana = new Banana();
IInterface b = (IInterface)banana;
}
}
반면에 바나나를 클래스로 캐스팅하려고하면 컴파일러는 메타 데이터를 확인하고 오류를 발생시킵니다.
FileStream fs = (FileStream)banana;
'Development Tip' 카테고리의 다른 글
jQuery val () 및 확인란 (0) | 2020.12.08 |
---|---|
Java의 System.in에서 읽는 가장 빠른 방법은 무엇입니까? (0) | 2020.12.08 |
Node.js에서 버퍼를 ReadableStream으로 변환 (0) | 2020.12.08 |
사용자 수준 스레드와 커널 지원 스레드의 차이점은 무엇입니까? (0) | 2020.12.08 |
부동 소수점 값을 변환 할 때 std :: to_string의 정밀도 설정 (0) | 2020.12.08 |