2013-08-15 4 views
9

Prima di tutto, mi spiace per il titolo, ma non riuscivo a pensare a nulla di meglio ...Generics e chiama metodo di overload dalla classe differenza - questione di precedenza

Il mio problema può essere presentata da codice di esempio semplice:

public static class Test<T> 
{ 
    public static int GetInt(T source) 
    { 
     return Convert.ToInt32(source); 
    } 
} 

public static class Convert 
{ 
    public static int ToInt32(byte source) 
    { 
     return 30; 
    } 

    public static int ToInt32(object source) 
    { 
     return 10; 
    } 
} 

Perché Console.WriteLine(Test<byte>.GetInt(20)); stampe 10, invece di 30?

Ho sempre pensato che i generici in .NET siano risolti da JIT durante il runtime. Perché allora il jitter non è abbastanza intelligente, per scoprire che esiste il metodo ToInt32(byte), che si adatta al nostro tipo di parametro byte qui?

Questo comportamento rende i metodi di classe statici Convert richiamare il risultato nelle operazioni di boxing/unboxing per i tipi semplici.

+0

'Test .GetInt (byte.Parse ("20"))' restituisce 10 così che trovo straniero, La finestra orologio dice che il tipo è oggetto {} byte che potrebbe dare qualche indizio su quello che sta succedendo – Sayse

risposta

7

Il compilatore deve decidere in fase di compilazione quale metodo scegliere. Non emette alcun codice per decidere in fase di esecuzione quale dei due sovraccarichi selezionare. Poiché non hai fornito alcuna prova al compilatore C# che GetInt(T source) funzioni solo con le strutture byte, il compilatore deve selezionare l'altro sovraccarico.

O lascia che lo metta in una prospettiva diversa: se rimuovi il sovraccarico di ToInt32(object), il tuo programma non riesce a compilare.

+0

C'è un modo per farlo chiamare il metodo 'byte' (o, in generale, il miglior metodo disponibile)? – MarcinJuraszek

+0

verifica per typeof (T) == typeof (byte) + cast per byte se true è l'unico modo – Vitaly

+0

@MarcinJuraszek: la boxe è davvero un problema? – Steven

0

compilatore decide al momento della compilazione il metodo da eseguire.

vedo attraverso Riflettore per codice IL e abbiamo trovato questo -

.method public hidebysig static int32 GetInt(!T source) cil managed 
{ 
    .maxstack 1 
    .locals init (
     [0] int32 CS$1$0000) 
    L_0000: nop 
    L_0001: ldarg.0 
    L_0002: box !T 
    L_0007: call int32 ConsoleApplication1.Convert::ToInt32(object) <-- HERE 
    L_000c: stloc.0 
    L_000d: br.s L_000f 
    L_000f: ldloc.0 
    L_0010: ret 
} 

Come menzionato da Jon Skeethere, è possibile effettuare una chiamata al metodo di byte utilizzando dynamic che fornisce digitato informazioni al momento dell'esecuzione invece del tempo di compilazione.

public static class Test<T> 
{ 
    public static int GetInt(T source) 
    { 
     dynamic dynamicSource = source; 
     return Convert.ToInt32(dynamicSource); 
    } 
}