Der wichtigste Unterschied zwischen a classund a structist, 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 Thingeiner Struktur und somePropertyOrFieldum ein verfügbares öffentliches Feld handelt, werden die Objekte thing1und thing2voneinander "getrennt", sodass sich die letztere Anweisung nicht auswirkt thing1. Wenn Thinges sich um eine Klasse handelt, werden thing1und thing2aneinander 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 Persones 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 Persones eine Struktur ist und man sie aktualisieren myPeoplemöchte, müsste man eindeutig so etwas tun myPeople.UpdatePerson("123-45-6789", somePerson). Wenn Persones 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. PhoneNumberStellen Sie sich zum Beispiel eine Struktur vor, deren Felder unter anderem AreaCodeund 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 PhoneNumberaußer AreaCodeund kennt oder kümmert Exchange. Wenn PhoneNumberes sich um eine sogenannte "unveränderliche" Struktur handeln würde, müsste entweder withXXfü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.