MSDN sagt, dass Sie Strukturen verwenden sollten, wenn Sie leichte Objekte benötigen. Gibt es andere Szenarien, in denen eine Struktur einer Klasse vorzuziehen ist?
Einige Leute haben das vielleicht vergessen:
- Strukturen können Methoden haben.
- Strukturen können nicht vererbt werden.
Ich verstehe die technischen Unterschiede zwischen Strukturen und Klassen, ich habe nur kein gutes Gefühl dafür, wann ich eine Struktur verwenden soll.
Antworten:
MSDN hat die Antwort: Auswahl zwischen Klassen und Strukturen .
Grundsätzlich enthält diese Seite eine Checkliste mit 4 Elementen und die Verwendung einer Klasse, sofern Ihr Typ nicht alle Kriterien erfüllt.
quelle
ref
Parameter, wann immer dies sinnvoll ist. Übergeben Sie eine Struktur mit 4.000 Feldern als ref-Parameter an eine Methode, die eines ändert. Dies ist billiger als das Übergeben einer Struktur mit 4 Feldern nach Wert an eine Methode, die eine geänderte Version zurückgibt.Ich bin überrascht, dass ich bei keiner der vorherigen Antworten dies gelesen habe, was ich für den wichtigsten Aspekt halte:
Ich verwende Strukturen, wenn ich einen Typ ohne Identität möchte. Zum Beispiel ein 3D-Punkt:
Wenn Sie zwei Instanzen dieser Struktur haben, ist es Ihnen egal, ob es sich um ein oder zwei einzelne Daten im Speicher handelt. Sie kümmern sich nur um die Werte, die sie enthalten.
quelle
return false
ist das, was dort hätte sein sollen und jetzt korrigiert.Bill Wagner hat ein Kapitel darüber in seinem Buch "effektiv c #" ( http://www.amazon.com/Effective-Specific-Ways-Improve-Your/dp/0321245660 ). Er schließt mit dem folgenden Prinzip:
quelle
Verwenden Sie eine Struktur, wenn Sie eine Werttypsemantik anstelle eines Referenztyps wünschen. Strukturen sind nach Wert kopiert, seien Sie also vorsichtig!
Siehe auch vorherige Fragen, z
Was ist der Unterschied zwischen Struktur und Klasse in .NET?
quelle
Ich würde Strukturen verwenden, wenn:
Ein Objekt soll schreibgeschützt sein (jedes Mal, wenn Sie eine Struktur übergeben / zuweisen, wird sie kopiert). Nur-Lese-Objekte eignen sich hervorragend für die Multithread-Verarbeitung, da sie in den meisten Fällen nicht gesperrt werden müssen.
Ein Objekt ist klein und kurzlebig. In einem solchen Fall besteht eine gute Chance, dass das Objekt auf dem Stapel zugewiesen wird, was viel effizienter ist als das Ablegen auf dem verwalteten Heap. Darüber hinaus wird der vom Objekt zugewiesene Speicher freigegeben, sobald er außerhalb seines Gültigkeitsbereichs liegt. Mit anderen Worten, es ist weniger Arbeit für Garbage Collector und der Speicher wird effizienter genutzt.
quelle
Verwenden Sie eine Klasse, wenn:
Verwenden Sie eine Struktur, wenn:
quelle
Ich habe immer eine Struktur verwendet, wenn ich einige Werte gruppieren wollte, um Dinge von einem Methodenaufruf zurückzugeben, aber ich muss sie für nichts verwenden, nachdem ich diese Werte gelesen habe. Nur um die Dinge sauber zu halten. Ich neige dazu, Dinge in einer Struktur als "wegwerfbar" und Dinge in einer Klasse als nützlicher und "funktionaler" anzusehen.
quelle
Wenn eine Entität unveränderlich sein soll, ist die Frage, ob eine Struktur oder eine Klasse verwendet werden soll, im Allgemeinen eher eine Frage der Leistung als der Semantik. Auf einem 32/64-Bit-System müssen für Klassenreferenzen 4/8 Byte gespeichert werden, unabhängig von der Informationsmenge in der Klasse. Das Kopieren einer Klassenreferenz erfordert das Kopieren von 4/8 Bytes. Auf der anderen Seite jeder andersDie Klasseninstanz hat zusätzlich zu den darin enthaltenen Informationen und den Speicherkosten der Verweise darauf 8/16 Byte Overhead. Angenommen, man möchte ein Array von 500 Entitäten, die jeweils vier 32-Bit-Ganzzahlen enthalten. Wenn es sich bei der Entität um einen Strukturtyp handelt, benötigt das Array 8.000 Byte, unabhängig davon, ob alle 500 Entitäten identisch, alle unterschiedlich oder irgendwo dazwischen sind. Wenn die Entität ein Klassentyp ist, benötigt das Array mit 500 Referenzen 4.000 Byte. Wenn diese Verweise alle auf unterschiedliche Objekte verweisen, benötigen die Objekte jeweils zusätzliche 24 Byte (12.000 Byte für alle 500), insgesamt 16.000 Byte - das Doppelte der Speicherkosten eines Strukturtyps. Wenn der Code hingegen eine Objektinstanz erstellt und dann einen Verweis auf alle 500 Array-Slots kopiert, betragen die Gesamtkosten für diese Instanz 24 Byte und 4, 000 für das Array - insgesamt 4.024 Bytes. Eine große Einsparung. Nur wenige Situationen würden so gut funktionieren wie die letzte, aber in einigen Fällen kann es möglich sein, einige Verweise auf genügend Array-Slots zu kopieren, damit sich eine solche Freigabe lohnt.
Wenn die Entität veränderbar sein soll, ist die Frage, ob eine Klasse oder eine Struktur verwendet werden soll, in gewisser Weise einfacher. Angenommen, "Thing" ist entweder eine Struktur oder eine Klasse mit einem ganzzahligen Feld namens x, und man führt den folgenden Code aus:
Möchte man, dass die letztere Aussage t1.x beeinflusst?
Wenn Thing ein Klassentyp ist, sind t1 und t2 äquivalent, was bedeutet, dass t1.x und t2.x ebenfalls äquivalent sind. Somit wirkt sich die zweite Anweisung auf t1.x aus. Wenn Thing ein Strukturtyp ist, sind t1 und t2 unterschiedliche Instanzen, was bedeutet, dass sich t1.x und t2.x auf unterschiedliche Ganzzahlen beziehen. Somit wirkt sich die zweite Anweisung nicht auf t1.x aus.
Veränderbare Strukturen und veränderbare Klassen verhalten sich grundlegend unterschiedlich, obwohl .net einige Besonderheiten im Umgang mit Strukturmutationen aufweist. Wenn Sie ein Verhalten vom Werttyp wünschen (was bedeutet, dass "t2 = t1" die Daten von t1 nach t2 kopiert, während t1 und t2 als unterschiedliche Instanzen belassen werden), und wenn Sie mit den Macken bei der Behandlung von Werttypen durch .net leben können, verwenden Sie eine Struktur. Wenn Sie eine Semantik vom Werttyp wünschen, die Macken von .net jedoch zu einer fehlerhaften Semantik vom Werttyp in Ihrer Anwendung führen würden, verwenden Sie eine Klasse und murmeln Sie.
quelle
Zusätzlich die hervorragenden Antworten oben:
Strukturen sind Werttypen.
Sie können niemals auf Nichts gesetzt werden .
Wenn Sie eine Struktur = Nothing festlegen, werden alle Wertetypen auf ihre Standardwerte gesetzt.
quelle
wenn Sie nicht wirklich Verhalten brauchen, aber mehr Struktur als ein einfaches Array oder Wörterbuch benötigen.
Follow-up So denke ich über Strukturen im Allgemeinen. Ich weiß, dass sie Methoden haben können, aber ich mag es, diese allgemeine mentale Unterscheidung beizubehalten.
quelle
Wie @Simon sagte, bieten Strukturen eine Semantik vom Typ "Wert". Wenn Sie also ein ähnliches Verhalten wie ein integrierter Datentyp benötigen, verwenden Sie eine Struktur. Da Strukturen als Kopie übergeben werden, sollten Sie sicherstellen, dass sie klein sind (ca. 16 Byte).
quelle
Es ist ein altes Thema, wollte aber einen einfachen Benchmark-Test liefern.
Ich habe zwei CS-Dateien erstellt:
und
Benchmark ausführen:
Ergebnisse:
quelle
Hmm ...
Ich würde die Garbage Collection nicht als Argument für / gegen die Verwendung von Strukturen gegen Klassen verwenden. Der verwaltete Heap funktioniert ähnlich wie ein Stapel. Wenn Sie ein Objekt erstellen, wird es einfach oben auf dem Heap platziert, was fast so schnell ist wie das Zuweisen auf dem Stapel. Wenn ein Objekt nur von kurzer Dauer ist und einen GC-Zyklus nicht überlebt, ist die Freigabe kostenlos, da der GC nur mit Speicher arbeitet, auf den noch zugegriffen werden kann. (Durchsuchen Sie MSDN, es gibt eine Reihe von Artikeln zur .NET-Speicherverwaltung. Ich bin einfach zu faul, um nach ihnen zu suchen.)
Die meiste Zeit, in der ich eine Struktur benutze, mache ich mir dafür einen Kick, weil ich später herausfinde, dass eine Referenzsemantik die Dinge ein bisschen einfacher gemacht hätte.
Wie auch immer, diese vier Punkte im oben veröffentlichten MSDN-Artikel scheinen eine gute Richtlinie zu sein.
quelle
class MutableHolder<T> { public T Value; MutableHolder(T value) {Value = value;} }
, und dann ist aMutableHolder<T>
ein Objekt mit veränderlicher Klassensemantik (dies funktioniert genauso gut, wennT
es sich um eine Struktur oder einen unveränderlichen Klassentyp handelt).Strukturen befinden sich auf dem Stapel und nicht auf dem Heap. Daher sind sie threadsicher und sollten bei der Implementierung des Übertragungsobjektmusters verwendet werden. Sie möchten niemals Objekte auf dem Heap verwenden. Sie sind flüchtig. In diesem Fall möchten Sie den Aufrufstapel verwenden. Dies ist ein grundlegender Fall für die Verwendung einer Struktur. Ich bin überrascht, wie viele Antworten hier vorliegen.
quelle
Ich denke, die beste Antwort ist einfach, struct zu verwenden, wenn Sie eine Sammlung von Eigenschaften benötigen, class, wenn es sich um eine Sammlung von Eigenschaften UND Verhaltensweisen handelt.
quelle