Der wichtigste Unterschied zwischen a class
und a struct
ist, was in der folgenden Situation passiert:
Sache thing1 = new Thing ();
thing1.somePropertyOrField = 5;
Sache thing2 = thing1;
thing2.somePropertyOrField = 9;
Auf was soll sich die letzte Aussage auswirken thing1.somePropertyOrField
? Wenn es sich bei Thing
einer Struktur und somePropertyOrField
um ein verfügbares öffentliches Feld handelt, werden die Objekte thing1
und thing2
voneinander "getrennt", sodass sich die letztere Anweisung nicht auswirkt thing1
. Wenn Thing
es sich um eine Klasse handelt, werden thing1
und thing2
aneinander angehängt, und so wird die letztere Anweisung geschrieben thing1.somePropertyOrField
. Eine Struktur sollte in Fällen verwendet werden, in denen die erstere Semantik sinnvoller wäre, und eine Klasse sollte in Fällen verwendet werden, in denen die letztere Semantik sinnvoller wäre.
Beachten Sie, dass einige Leute raten, dass der Wunsch, etwas veränderbar zu machen, ein Argument dafür ist, dass es die Klasse ist. Ich würde jedoch das Gegenteil vermuten: Wenn etwas existiert, um einige Daten zu speichern, wird es veränderbar sein, und Wenn nicht klar ist, ob Instanzen an irgendetwas gebunden sind, sollte das Ding eine Struktur sein (wahrscheinlich mit exponierten Feldern), um zu verdeutlichen, dass Instanzen an nichts anderes gebunden sind.
Betrachten Sie zum Beispiel die Anweisungen:
Person somePerson = myPeople.GetPerson ("123-45-6789");
somePerson.Name = "Mary Johnson"; // War "Mary Smith"
Ändert die zweite Anweisung die in gespeicherten Informationen myPeople
? Wenn Person
es sich um eine Struktur mit exponierten Feldern handelt, wird dies nicht der Fall sein , und die Tatsache, dass dies nicht der Fall ist, ist eine offensichtliche Folge davon, dass es sich um eine Struktur mit exponierten Feldern handelt . Wenn Person
es eine Struktur ist und man sie aktualisieren myPeople
möchte, müsste man eindeutig so etwas tun myPeople.UpdatePerson("123-45-6789", somePerson)
. Wenn Person
es sich jedoch um eine Klasse handelt, ist es möglicherweise viel schwieriger zu bestimmen, ob der obige Code den Inhalt von niemals aktualisieren MyPeople
, immer aktualisieren oder manchmal aktualisieren würde.
In Bezug auf die Vorstellung, dass Strukturen "unveränderlich" sein sollten, bin ich im Allgemeinen anderer Meinung. Es gibt gültige Anwendungsfälle für "unveränderliche" Strukturen (bei denen Invarianten in einem Konstruktor erzwungen werden), aber es ist umständlich, verschwenderisch und eher dazu geneigt, Fehler zu verursachen, als sie nur anzuzeigen Felder direkt. PhoneNumber
Stellen Sie sich zum Beispiel eine Struktur vor, deren Felder unter anderem AreaCode
und umfassen Exchange
, und nehmen Sie an, eine hat ein List<PhoneNumber>
. Der Effekt des Folgenden sollte ziemlich klar sein:
für (int i = 0; i <myList.Count; i ++)
{
PhoneNumber theNumber = myList [i];
if (theNumber.AreaCode == "312")
{
string newExchange = "";
if (new312to708Exchanges.TryGetValue (theNumber.Exchange), out newExchange)
{
theNumber.AreaCode = "708";
theNumber.Exchange = newExchange;
myList [i] = theNumber;
}
}
}
Beachten Sie, dass der obige Code keine Felder PhoneNumber
außer AreaCode
und kennt oder kümmert Exchange
. Wenn PhoneNumber
es sich um eine sogenannte "unveränderliche" Struktur handeln würde, müsste entweder withXX
für jedes Feld eine Methode angegeben werden, die eine neue Strukturinstanz zurückgibt, die den übergebenen Wert im angegebenen Feld enthält, oder es wäre erforderlich für Code wie den obigen, um über jedes Feld in der Struktur Bescheid zu wissen. Nicht gerade ansprechend.
Übrigens gibt es mindestens zwei Fälle, in denen Strukturen möglicherweise Verweise auf veränderbare Typen enthalten.
- Die Semantik der Struktur gibt an, dass sie die Identität des betreffenden Objekts speichert und nicht als Abkürzung zum Speichern der Objekteigenschaften. Zum Beispiel würde ein "KeyValuePair" die Identitäten bestimmter Schaltflächen enthalten, es wird jedoch nicht erwartet, dass es dauerhafte Informationen über die Positionen dieser Schaltflächen, Hervorhebungszustände usw. enthält.
- Die Struktur weiß, dass sie die einzige Referenz auf dieses Objekt enthält, niemand anderes wird eine Referenz erhalten, und alle Mutationen, die jemals an diesem Objekt durchgeführt werden, werden durchgeführt, bevor eine Referenz darauf irgendwo gespeichert wird.
Im ersten Szenario ist die IDENTITÄT des Objekts unveränderlich. Im zweiten Fall erzwingt die Klasse des verschachtelten Objekts möglicherweise keine Unveränderlichkeit, während die Struktur, die die Referenz enthält, dies tut.