Domanda

Sto solo cercando di farmi girare la testa su Generics leggendo questo articolo illuminante di Juval Lowy

Parafrasando .. Quando si definisce una definizione di classe generica, questa viene compilata in IL.

  • Per i tipi di valore, non appena si richiede un tipo di valore specifico, sostituisce la T con il tipo di valore specifico per ottenere l'IL per quella specifica configurazione, ad es. MyList<int> Vantaggio: nessuna penalità di boxe e unboxing.
  • Tutto bene .. per i tipi di riferimento, il compilatore sostituisce tutte le istanze di T nella tua definizione con Object e crea l'IL che viene utilizzato per tutti i tipi di riferimento. Tuttavia, le istanze vengono assegnate in base al tipo di riferimento effettivo richiesto, ad es. MyList<String>

Ora pre-generici avremmo potuto scrivere metodi che accettano Object parametri. Generics afferma il 100% di miglioramento delle prestazioni perché " evita la penalità di prestazione che incorre quando si abbassa il tipo di oggetto al tipo specifico quando si desidera utilizzarlo"

 // assume GetItem returns an Object
 string sMyPreciousString = (string) obList.GetItem(); 

Qual è il risultato di questa prestazione quando si esegue il downcast da Object a un tipo di riferimento specifico? Inoltre sembra che l'upgrade a Object (anche Generics farebbe questo) non sia un successo da prestazione .. perché?

È stato utile?

Soluzione

L'upgrade all'oggetto non richiede un controllo del tempo di esecuzione: funzionerà sempre ed è sostanzialmente una non-operazione.

Il downcasting richiede un controllo del tempo di esecuzione per assicurarsi, ad esempio, di non trasmettere un flusso a una stringa. È una penalità piuttosto piccola e molto improbabile che sia un collo di bottiglia, ma evitarlo è solo un vantaggio in più per i generici.

Altri suggerimenti

Il successo delle prestazioni deriva dalla necessità di un controllo del tipo di runtime. Se B è una sottoclasse di A, quindi quando lanci una B in una A, sai al momento della compilazione che sarà sicuro, poiché tutti i Bs sono As. Pertanto, non è necessario generare alcun codice di runtime per verificare il tipo.

Tuttavia, quando lanci una A in una B, non sai al momento della compilazione se A è effettivamente una B o no. Potrebbe essere solo una A, potrebbe essere di tipo C, un sottotipo diverso di A. Pertanto, è necessario generare un codice di runtime che assicurerà che l'oggetto sia effettivamente una B e generare un'eccezione se non lo è.

I generici non hanno questo problema, perché il compilatore sa, al momento della compilazione, che solo i Bs sono stati inseriti nella struttura dei dati, quindi quando si estrae qualcosa, il compilatore sa che sarà una B, quindi non c'è necessità del controllo del tipo in fase di esecuzione.

Leggendo sull'IL che viene generato (questo articolo lo menziona). .. aha - isinst.

Se non stavi eseguendo il downcast, non dovresti chiamare isinst .

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top