2015-11-10 20 views
5

I commenti forniti nel source code per IList, IEnumerable e ICollection diceScopo di TypeDependencyAttribute ("System.SZArrayHelper") per IList <T>, IEnumerable <T> e ICollection <T>?

noti che T[] : IList<T>, e vogliamo assicurare che se si utilizza IList<YourValueType>, possiamo garantire un YourValueType[] può essere utilizzato senza jitting. Da qui il TypeDependencyAttribute su SZArrayHelper. Questo è un trucco speciale internamente però - vedi VM \ compile.cpp.

Perché IList<T> contengono una dipendenza SZArrayHelper?. Capisco che SZArrayHelper è un wrapper CLR attorno a un array che implementa l'interfaccia IList<T> ma non riesco a ottenere il quadro completo del motivo per cui questi due sono legati insieme.

E come si può garantire che YourValueType[] possa essere utilizzato senza jitting.?

+0

Probabilmente a causa 99,9% degli incassi utilizzare un array per lo storage a un certo livello, in modo da 'ragionevole richiedere tale dipendenza. Questo ti sta causando un problema o sei solo curioso? –

+0

@DStandley: Curioso .. ma di nuovo come fa a garantire che YourValueType [] possa essere usato senza jittare? – NullReference

+1

Non si tratta di 'YourValueType []' * stesso *. Si tratta di usarlo quando lanciato nella corrispondente interfaccia generica. 'int []' * non * implementa effettivamente 'IEnumerable .GetEnumerator' anche se appare come se fosse così - l'effettiva implementazione è in quella misteriosa classe' SZArrayHelper'. – Luaan

risposta

9

È un hack nella JIT, come indicato nella tua citazione. Quando la macchina virtuale rileva che è presente uno, tratta la classe in modo diverso, consentendo di utilizzare un codice più efficiente.

Guardando il codice rilevante nella VM (nota che sto utilizzando una versione più vecchia pubblica qui - non il attuale NET VM):

Una chiamata a una matrice attraverso IList (o IEnumerable o ICollection) deve essere gestito in modo speciale. Queste interfacce sono "magia" (per lo più a causa di working set in questione - sono creati su richiesta internamente anche se semanticamente, queste sono interfacce statiche.)

Gli array sono un po 'di hack in .NET nel primo posto. Quando sono state aggiunte le interfacce generiche, questo ha rappresentato un piccolo problema: ad esempio, int[] è un Array, ma è anche un tipo speciale e un array di int; questo consentiva agli array di essere generici prima che fossero aggiunti i tipi generici reali.

Ora, vediamo un esempio concreto. Hai un int[] e vuoi usarlo in LINQ. Dal momento che int[] implementa IEnumerable<int>, ti dà tutta la potenza di LINQ, fuori dalla scatola, e si può scrivere qualcosa del genere:

var positiveNumbers = numbers.Where(i => i > 0); 

Dal punto di vista C# 's, non c'è nessun problema. Tuttavia, dal punto della parte interna della macchina virtuale, questo è un grosso problema, perché int[] non è in realtà implementa IEnumerable<int>! Anche dopo aver introdotto i generici su .NET (e C#), gli array vengono ancora gestiti alla vecchia maniera.

L'hack deve utilizzare SZArrayHelper per gestire uno di questi metodi generici. Quindi, ad esempio, chiama GetEnumerator internamente allo IEnumerable<int>. La VM rileva che stai cercando di chiamare GetEnumerator su un array e invece di inviare virtualmente GetEnumerator nell'istanza dell'array, reindirizza la chiamata a SZArrayHelper.GetEnumerator<int>().

Questo è un enorme mod - se si guarda il codice di riferimento per SZArrayHelper, troverete tonnellate di avvertimenti - per esempio, il metodo GetEnumerator<int> è un metodo di istanza, ma è this argomento è in realtà la matrice (ad esempio int[]), non SZArrayHelper.

Ma ci permette di trattare le matrici come se si attuino effettivamente tutte quelle interfacce generiche - anche se non :)

+0

Brillante !!!. Mai però in questo modo. – NullReference

Problemi correlati