2010-05-25 9 views
6

Ho notato in C#, a differenza del C++, è possibile combinare metodi virtuali e generici. Per esempio:Prestazioni del polimorfismo del metodo C# con i generici

using System.Diagnostics; 

class Base { 
    public virtual void Concrete() {Debug.WriteLine("base concrete");} 
    public virtual void Generic<T>() {Debug.WriteLine("base generic");} 
} 

class Derived : Base { 
    public override void Concrete() {Debug.WriteLine("derived concrete");} 
    public override void Generic<T>() {Debug.WriteLine("derived generic");} 
} 

class App { 
    static void Main() { 
     Base x = new Derived(); 
     x.Concrete(); 
     x.Generic<PerformanceCounter>(); 
    } 
} 

Dato che qualsiasi numero di versioni di Generic<T> potrebbe essere istanziato, ma non sembra che l'approccio standard vtbl potrebbe essere utilizzato per risolvere chiamate di metodo, e in effetti non lo è. Ecco il codice generato:

 x.Concrete(); 
mov   ecx,dword ptr [ebp-8] 
mov   eax,dword ptr [ecx] 
call  dword ptr [eax+38h] 
     x.Generic<PerformanceCounter>(); 
push  989A38h 
mov   ecx,dword ptr [ebp-8] 
mov   edx,989914h 
call  76A874F1 
mov   dword ptr [ebp-4],eax 
mov   ecx,dword ptr [ebp-8] 
call  dword ptr [ebp-4] 

Il codice aggiuntivo sembra essere alla ricerca di un vtbl dinamica secondo i parametri generici, e quindi chiamando in esso. Qualcuno ha scritto sulle specifiche di questa implementazione? Quanto bene si comporta rispetto al caso non generico?

risposta

3

L'implementazione di generics .NET può gestire facilmente uno scenario di questo tipo e con prestazioni molto buone. Ho scritto un blog post a riguardo qualche tempo fa.

Una delle migliori risorse per trovare informazioni su come il CLR implementa i generici è questa paper di Micosoft Research.

Hai capito bene il vtable. Il modo in cui il CLR crea codice eseguibile per un tipo generico quando il compilatore JIT incappa su uno, dipende dal parametro di tipo generico. La gestione è diversa per tipi di valore e tipi di riferimento.

Mentre il codice eseguibile (l'istanza, l'immagine nativa) è condiviso tra le istanze per tutti i parametri di tipo generico che sono tipi di riferimento, il vtable associato a un'istanza (oggetto) dell'istanza è univoco al tipo di parametro concreto.

Ecco la citazione pertinente dal documento sopra citato:

4,2 rappresentazione dell'oggetto oggetti in mucchio garbage collection del CLR sono rappresentato da un puntatore vtable seguita da contenuti dell'oggetto (es fi campi o matrice elementi). Il ruolo principale di vtable è il metodo virtuale dispatch: contiene un puntatore di codice per ogni metodo definito o ereditato dalla classe dell'oggetto. Ma per tipi di classi semplici, almeno, in corrispondenza della corrispondenza uno a uno tra, può essere utilizzato anche per rappresentare il tipo di oggetto. Quando viene utilizzato il vtable in questo modo, lo chiamiamo handle del tipo.In un implementazione del polimorfismo basato sulla piena la specializzazione, la nozione di esatto tipo run-time viene gratuitamente come diverse istanze dello stesso tipo parametrico hanno diversi VTables. Ma supponiamo ora che il codice sia condiviso tra diversi interni come List<string> e List<object>. I vtables per le due istanze di saranno identici, , quindi abbiamo bisogno di un modo per rappresentare l'istanziazione in fase di esecuzione.

...

[Per ogni esemplificazione, abbiamo] Sostituire il puntatore vtable da un puntatore ad una struttura e-esemplificazione combinato vtable- e duplicarlo [la struttura] per ogni istanziazione.

+0

Esattamente quello che stavo cercando, grazie! – zildjohn01

0

Il modo in cui i generici .NET vengono implementati, per ogni utilizzo di una classe generica (o metodo), il CLR crea una nuova implementazione di tale classe (o metodo) con il parametro generico inserito. Per i tipi di riferimento, tutti condividere una singola implementazione (poiché sono tutti solo indicatori della stessa dimensione); le strutture hanno ciascuna la propria implementazione in quanto le dimensioni sono tutte diverse.

Quindi immagino che ogni implementazione di un tipo/metodo generico abbia anche il proprio vtable, e che il codice stia facendo una 'implementazione generica di ricerca', quindi una 'sostituzione vtable di ricerca' sull'implementazione che trova.

Problemi correlati