Development Tip

C # 컴파일러가 IEnumerable 간의 명시 적 캐스트를 허용하는 이유

yourdevel 2020. 12. 8. 20:05
반응형

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;

컴파일러는 이러한 각각의 구체적인 클래스 ( BananaList<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;

참고 URL : https://stackoverflow.com/questions/9198024/why-does-the-c-sharp-compiler-allow-an-explicit-cast-between-ienumerablet-and

반응형