Lassen Sie uns zunächst die Leistungsfragen ignorieren und uns langsam an sie herantasten.
Structs sind ValueTypes und ValueTypes sind Werttypen. Integer und DateTime
sind Werttypen und ein guter Vergleich. Es macht keinen Sinn, darüber zu sprechen, ob eine 1
gleich oder ungleich einer anderen 1
ist, oder ob eine 2010-02-03T12:45:23.321Z
gleich oder ungleich einer anderen 2010-02-03T12:45:23.321Z
ist. Sie haben in verschiedenen Anwendungen unterschiedliche Bedeutungen, aber dass 1 == 1 und 1 != 2 ist, und dass 2010-02-03T12:45:23.321Z == 2010-02-03T12:45:23.321Z und 2010-02-03T12:45:23.321Z != 2931-03-05T09:21:29.43Z ist in der Natur von Ganzzahlen und Datum/Zeit enthalten und das macht sie zu Werttypen.
Das ist die reinste Art, darüber nachzudenken. Wenn es mit dem oben Genannten übereinstimmt, ist es ein Werttyp, wenn nicht, ist es ein Verweistyp. Nichts anderes spielt dabei eine Rolle.
Erweiterung 1: Wenn ein X ein X haben kann, muss es sich um einen Verweistyp handeln. Ob das logisch aus dem oben Gesagten folgt, ist diskutabel, aber was auch immer Sie zu dieser Frage denken, Sie können keine Struktur haben, die eine Instanz von sich selbst als Mitglied hat (direkt oder indirekt) in der Praxis, also das ist das.
Erweiterung 2: Einige sagen, dass die Schwierigkeiten, die von veränderbaren Strukturen herrühren, von dem oben Gesagten kommen, und manche nicht. Wie auch immer Sie zu dieser Frage stehen, es gibt praktische Schwierigkeiten. Eine veränderbare Struktur kann in einigen Fällen nützlich sein, aber sie verursachen genug Verwirrung, dass sie auf private Fälle als Optimierung beschränkt werden sollten, anstatt auf öffentliche Fälle als Regel.
Hier kommt der Leistungsaspekt...
Werttypen und Verweistypen haben in verschiedenen Fällen unterschiedliche Eigenschaften, die die Geschwindigkeit, den Speicherverbrauch und die Art und Weise beeinflussen, wie der Speicherverbrauch die Garbage Collection in mehreren Hinsichten beeinflusst, wodurch jeder verschiedene Vor- und Nachteile in Bezug auf die Leistung hat. Wie viel Aufmerksamkeit wir diesem Aspekt schenken, hängt davon ab, wie sehr wir uns auf diese Ebene einlassen müssen. Es lohnt sich zu sagen, dass die Unterschiede tendenziell zu einem Gewinn führen, wenn Sie sich an die obige Regel halten, um zwischen Struktur und Klasse zu entscheiden. Wenn wir darüber hinaus über dieses Thema nachdenken, bewegen wir uns zumindest in Richtung Optimierung.
Optimierungsstufe 1.
Wenn eine Werttyp-Instanz mehr als 16 Bytes pro Instanz enthält, sollte sie wahrscheinlich zu einem Verweistyp gemacht werden. Dies wird manchmal sogar als "natürlicher" Unterschied und nicht als Optimierung betrachtet. Streng genommen gibt es nichts im Begriff "Werttyp", das "16 oder weniger Bytes" impliziert, aber es neigt dazu, sich so auszugleichen.
Abgesehen von der simplen "16-Byte"-Regel, je kleiner es ist, desto schneller ist es zu kopieren. Werden Sie also viele Boxen machen müssen? Seit der Einführung von Generics konnten wir viele Fälle vermeiden, in denen wir mit 1.0 und 1.1 boxen mussten, daher ist das nicht mehr so ein großes Thema wie früher, aber wenn Sie es tun, wird es die Leistung beeinträchtigen.
Optimierungsstufe 2.
Die Tatsache, dass Werttypen auf einem Stack platziert werden können, direkt in einem Array platziert werden können (anstatt Referenzen dazu) und direkte Felder einer Struktur oder Klasse sein können (wiederum ohne Referenzen dazu), kann den Zugriff auf sie und ihre Felder schneller machen.
Wenn Sie ein Array von ihnen erstellen und wenn Nullwerte einen nützlichen Ausgangspunkt für Sie darstellen, erhalten Sie diesen unmittelbar, während Sie bei Verweistypen ein Array von Nullen erhalten. Dies kann Strukturen schneller machen.
Bearbeitung: Etwas, das sich aus dem Obigen ergibt, wenn Sie schnell durch Arrays iterieren, dann, zusätzlich zu dem direkten Zugriff, der einen Schub gegenüber dem Folgen des Verweises gibt, laden Sie ein paar Instanzen jedes Mal in den CPU-Cache (64 Bytes auf aktuellen x86-32 oder x86-64/amd, 128 Bytes auf ia-64). Es muss eine ziemlich enge Schleife sein, damit es eine Rolle spielt, aber es gibt Fälle, in denen es wichtig ist.
Praktisch gesagt, die meisten Fälle von "Ich habe mich für eine Struktur anstelle einer Klasse entschieden, um die Leistung zu verbessern" basieren entweder auf dem ersten Punkt oder dem ersten in Kombination mit dem zweiten.
Optimierungsstufe 3.
Wenn einige der Werte, die Sie interessieren, Duplikate voneinander sind und sie groß sind, dann können Sie mit unveränderlichen Instanzen (oder veränderbare Instanzen, die Sie einfach niemals ändern, sobald Sie mit dem, was folgt, beginnen) bewusst unterschiedliche Verweise aliasen, um viel Speicher zu sparen, weil Ihre z. B. 20 duplizierten Objekte von je 2 KiB tatsächlich dasselbe Objekt sind, wodurch in diesem Fall 26 KiB gespart werden. Dies kann auch Vergleiche schneller machen, weil die Fälle, in denen Sie auf Identität Abkürzungen machen können, häufiger sind. Dies kann nur mit Verweistypen erfolgen.
Optimierungsstufe 4.
Strukturen, die Arrays enthalten, könnten jedoch das enthaltene Array aliasen und intern die oben genannte Technik verwenden, was diesen Punkt ausgleicht, obwohl dies etwas komplizierter ist.
Optimierungsstufe X.
Es spielt keine Rolle, wie viel Nachdenken über diese Vor- und Nachteile zu einer bestimmten Antwort führt, wenn tatsächlich das Messen der Ergebnisse zu Unterschieden führt. Da es sowohl Vor- als auch Nachteile gibt, ist es immer möglich, sich zu irren.
Beim Nachdenken über 1 bis 4, zusammen mit den Unterschieden zwischen Wert- und Verweistypen abgesehen von solchen Optimierungsüberlegungen, denke ich, dass Sie sich für eine Klasse entscheiden sollten.
Beim Nachdenken über Stufe X würde es mich nicht überraschen, wenn Ihre tatsächliche Testung mich widerlegen würde. Der beste Teil ist, wenn es mühsam ist, von einer Klasse auf eine Struktur zu wechseln (Sie machen von Aliasierung oder der Möglichkeit eines Nullwertes starken Gebrauch), dann können Sie recht zuversichtlich sein, dass dies ein Verlust ist. Wenn es nicht mühsam ist, können Sie einfach wechseln und messen! Ich würde dringend empfehlen, einen Test zu messen, bei dem Sie tatsächlich etwas ausführen anstelle etwas 10.000 mal zu wiederholen - was spielt es für eine Rolle, wenn Sie eine bestimmte Operation ein paar Sekunden lang 10.000 Mal schneller ausführen können, wenn Sie eine andere Operation in der Realität 20 Mal häufiger durchführen?