[c#] Perché il compilatore C # consente un cast esplicito tra IEnumerable <T> e TAlmostAnything?



1 Answers

Quando dici Y y = (Y)x; questo cast dice al compilatore "fidati di me, qualunque sia x , in fase di esecuzione può essere lanciato su una Y , quindi, fallo, ok?"

Ma quando dici

List<Banana> aBunchOfBananas = new List<Banana>();
Banana justOneBanana = (Banana)aBunchOfBananas;

il compilatore può guardare le definizioni di ciascuna di queste classi concrete ( Banana e List<Banana> ) e vedere che non esiste un static explicit operator Banana(List<Banana> bananas) definito (ricorda, un cast esplicito deve essere definito in entrambi il tipo di essere castato o il tipo di essere castato, questo è dalla specifica, sezione 17.9.4). Sa al momento della compilazione che quello che stai dicendo non può mai essere vero. Quindi ti urla di smettere di mentire.

Ma quando dici

IEnumerable<Banana> aBunchOfBananas = new List<Banana>();
Banana justOneBanana = (Banana)aBunchOfBananas;

bene, ora il compilatore non lo sa. Molto bene potrebbe essere il caso che qualunque aBunchOfBananas sia aBunchOfBananas in fase di esecuzione, il suo tipo concreto X potrebbe aver definito l' static explicit operator Banana(X bananas) . Quindi il compilatore si fida di te, come lo hai chiesto tu.

Question

Il seguente codice ti dà un errore del compilatore, come ti aspetteresti:

List<Banana> aBunchOfBananas = new List<Banana>();

Banana justOneBanana = (Banana)aBunchOfBananas;

Tuttavia, quando si utilizza IEnumerable<Banana> , si ottiene semplicemente un errore di runtime.

IEnumerable<Banana> aBunchOfBananas = new List<Banana>();

Banana justOneBanana = (Banana)aBunchOfBananas;

Perché il compilatore C # consente questo?




Secondo le specifiche del linguaggio (6.2.4) "Le conversioni di riferimento esplicite sono: Da qualsiasi tipo di classe S a qualsiasi tipo di interfaccia T, a condizione che S non sia sigillato e che S non implementi T ... Le conversioni di riferimento esplicite sono quelle conversioni tra tipi di riferimento che richiedono controlli di runtime per garantire che siano corretti ... "

Quindi il compilatore non controlla la realizzazione dell'interfaccia durante la compilazione. Fa CLR in runtime. Controlla i metadati cercando di trovare la realizzazione in classe o tra i suoi genitori. Non so perché si comporta così. Probabilmente ci vuole un sacco di tempo. Quindi questo codice viene compilato correttamente:

public interface IInterface
{}

public class Banana
{
}

class Program
{
    static void Main( string[] args )
    {
        Banana banana = new Banana();

        IInterface b = (IInterface)banana;
    }
}

D'altra parte, se proviamo a lanciare banana in classe, il compilatore verifica i suoi metadati e genera un errore:

 FileStream fs = (FileStream)banana;



Related