2015-12-16 111 views
5
.method public static void Test<class T>(object A_0) cil managed 
{ 
    // Code size  13 (0xd) 
    .maxstack 1 
    .locals init (!!T V_0) 
    IL_0000: ldarg.0 
    IL_0001: isinst  !!T 
    IL_0006: unbox.any !!T 
    IL_000b: stloc.0 
    IL_000c: ret 
} // end of method DemoType::Test 

Il codice C# è uguale:CIL unbox_any istruzione - strano comportamento

public static void Test<T>(object o) where T : class 
{ 
    T t = o as T; 
} 

Le mie domande sono:

  1. Perché unbox.any stato chiamato? se lo farete

    var a = father as child 
    

    isinst intruction chiamerà e non unbox.any, e se io ti tolgo la definizione generica e cercherò di gettare (isinst) l'oggetto da qualche classe, non unbox.any sarà chiamato.

  2. Forse unbox.anche è stato chiamato perché la definizione generica, quindi in questo caso l'unbox.anche bisogno di lanciare un NullReferenceException perché la risposta di isinst istruzione restituisce null per questo casting. vedi unbox_any. E se provi ad eseguire questo codice, vedrai che nessuna eccezione è stata lanciata.

Aggiornamento

posso capire il unbox_any becuase il parametro tipo di oggetto e cercare di gettarlo ai tipo concreto dopo il controllo isinst. Forse anche l'influenza dei generici.

La mia domanda è, perché non lanciare un'eccezione in unbox.any se l'obj proviamo a unbox su T è nullo?

La documentazione dice: "NullReferenceException viene generata se obj è un riferimento null."

+0

Puoi elaborare ciò che è così strano? Per me ha senso. Al punto (2) non hai fatto una domanda, neanche. – usr

+0

@usr Primo, voglio verificare perché unbox_any è stato chiamato. Che senso ha chiamarli entrambi? (isinst e unbox_any) Secondo, e ancora più importante, perché nessuna eccezione generata se obj è passata a unbox_any è nullo? –

risposta

4

L'unbox serve a rendere felice il verificatore. Il verificatore non è particolarmente intelligente nel sapere che un parametro di tipo T diventerà sempre un tipo di riferimento, e quindi il compilatore C# emetterà queste unbox altrimenti inutili.

Se si esegue una ricerca del codice sorgente Roslyn per Unbox_any e IsVerifierReference, si vedrà che ciò accade in alcuni punti attorno al generatore di codice.

Il jitter saprà quando si genera il codice, indipendentemente dal fatto che il parametro type sia o meno un riferimento e debba generare un codice decente indipendentemente dall'istruzione apparentemente non necessaria.

+1

Se qualcuno è interessato a questo suggerisco di dare un'occhiata [qui] (http://stackoverflow.com/questions/34382683/jitter-logic-to-remove-unbox-any?lq=1) per l'immagine completa –