2010-11-03 14 views
9

Gibt es eine gute Möglichkeit, ein Array fester Größe in .NET zu implementieren, die keinen unsicheren Code erfordert?Sind effiziente Arrays fester Größe möglich, ohne unsicheren Code in .NET zu verwenden?

Mein Ziel ist es, einen Werttyp zu erstellen, der ein Array fester Größe darstellt, das in andere Typen eingebettet (eingeschlossen) werden kann - dh ich hoffe speziell, ein Array nicht als eigenständiges Objekt zu erstellen Typ, der es erklärt.

Ich weiß, dass .NET-Implementierung von Arrays ist hervorragend und unterstützt auf CLR/CIL-Ebene - und nicht wirklich darüber diskutieren wollen, ob oder nicht nur Arrays verwenden ... die Untersuchung hier ist, ob ein Safe , feste Größe, Werttyp Implementierung ist möglich mit fast so gut Effizienz.

+2

Können Sie mir helfen zu verstehen, welchen Vorteil dies bietet, dass ein gewöhnliches Array (innerhalb des Typs deklariert) nicht kann? Es ist schwierig, eine alternative Implementierung zu finden, wenn ich nicht einmal weiß, was das Ziel ist. Geht es darum, einige der Einwände gegen die hier beschriebenen Arrays zu beseitigen ?: http://blogs.msdn.com/b/ericlippert/archive/2008/09/22/arrays-consided-somewhat-harmful.aspx –

+1

@Robert: The Ziel ist es, in der Lage zu sein, ein Array vom Typ fester Größe zu haben, das als privates Mitglied auf anderen Typen verwendet werden kann. Stellen Sie sich ein benutzerdefiniertes Wörterbuch oder eine Implementierung einer verknüpften Liste vor ... Die Anzahl der Heapzuweisungen kann reduziert werden, wenn jeder Bucket/Node flachgelegt wird, um sein eigenes Array fester Größe zu enthalten. – Mark

Antwort

5

Das Ziel ist in der Lage sein, hat eine feste Größe Wert Array-Typs, die verwendet werden können, als privates Mitglied Arten auf andere. Betrachten Sie ein Benutzerwörterbuch oder verketteten Liste Implementierung ... die Anzahl der Heapzuweisungen kann reduziert, wenn jeder Eimer/Knoten enthalten abgeflacht es selbst ist, feste Größe Array.

Wenn Sie Ihr Array zu einem Werttyp machen, bedeutet dies nicht unbedingt, dass es auf dem Stack gespeichert wird. Wenn es sich um einen Werttyp handelt, der in einen Referenztyp eingebettet ist, wird er höchstwahrscheinlich auf dem Heap mit dem Referenztyp und nicht auf dem Stapel gespeichert.

Wenn Sie also einen Werttyp festlegen, werden die Heapzuweisungen überhaupt nicht reduziert.

Mehr Infos hier: http://blogs.msdn.com/b/ericlippert/archive/2010/09/30/the-truth-about-value-types.aspx

+0

Yup, das wird auf dem Haufen landen. Und er wird diese 512-Byte-Struktur viele Male kopieren, ohne Zweifel. –

+2

Das Idea hinter dieser Frage war speziell darauf ausgerichtet, die Struktur in eine Klasse einzubetten und die Struktur auf dem Heap mit der Klasse zu versehen. Wenn es als privates Mitglied implementiert und korrekt verwendet wird, sollte es nicht oft kopiert werden. – Mark

+1

... und es wird Heap-Zuordnungen reduzieren, da es jetzt nur einmal (für die enthaltene Klasse) und nicht erneut für das Array reserviert. –

2

Nach einigen Recherchen Reflektor, es stellt sich heraus, dass die nachfolgende Tabelle zeigt eine akzeptable (Performance-weise) Lösung, da C# eine switch-Anweisung gegen ganzen Zahlen in ein CIL switch-Anweisung erstellt, die ist als Sprungliste implementiert ... das heißt - der Getter führt in etwa 11 CIL-Anweisungen aus, was gut ist.

public struct EmbeddedArray<T> 
    { 
     private T _element0; 
     private T _element1; 
     private T _element2; 

     public int Length { get { return 3; } } 


     public T this[int index] 
     { 
      get 
      { 
       switch (index) 
       { 
        case 0: 
         return _element0; 
        case 1: 
         return _element1; 
        case 2: 
         return _element2; 
       } 
       throw new ArgumentOutOfRangeException("index"); 

      } 
     } 
    } 

Bitte sehen Hans' unter Kommentar. Es stellt sich heraus, dass dies ist nicht so performant, wie ich es mir erhofft hatte ... sobald die CIL auf nativen Maschinencode kompiliert ist, ist die gemessene Leistung weit entfernt, was ein .NET-Array ergeben wird.

+6

Wenn man IL betrachtet, ist das bedeutungslos, nur der Maschinencode, den der Jitter erzeugt, ist relevant. Und dieser Code sollte eine * Menge * schlechter als ein Array-Index durchführen. Es hat sehr schlechte Cache-Lokalität aufgrund der großen Jump-Tabelle. Und eine fast garantierte Verzweigungsprädiktion, die auf modernen Kernen * sehr * teuer ist. Ein Array-Index hat keines dieser Probleme. Profil es, um dies zu sehen, verwenden Sie echte Daten. –

+1

@Hans - Viel Respekt wieder für Ihren Kommentar. Adfter macht ein wenig Profiling, es stellt sich heraus, dass Sie in der Tat richtig sind ... die IL-Switch-Anweisung war ein wenig irreführend. Außerdem sind die Kosten der Zuweisung eines Arrays separat von der Klasse, die es verwendet, ein sehr günstiger Preis, um die Leistungssteigerungen eines Arrays zu bezahlen. Daumen hoch, Hans - ich wünschte, du hättest eine Antwort auf einen Kommentar geschrieben - es wäre die akzeptierte Antwort hier. – Mark

+1

Der letzte Absatz in Ihrer Frage schloss die Möglichkeit aus, über die richtige Antwort zu sprechen. –