Strukturentwurf
Aktualisiert: November 2007
Strukturen sind Werttypen. Sie werden auf dem Stapel oder inline reserviert und freigegeben, wenn sie den Gültigkeitsbereich verlassen. Im Allgemeinen können Werttypen mit weniger Aufwand reserviert und freigegeben werden. Wenn sie jedoch in Szenarien verwendet werden, in denen Boxing und Unboxing in wesentlichem Umfang erfolgt, ist ihre Leistung im Vergleich zu Verweistypen gering. Weitere Informationen finden Sie unter Boxing und Unboxing (C#-Programmierhandbuch).
Weitere Informationen über Werttypen und Verweistypen finden Sie unter Übersicht über das allgemeine Typsystem.
Stellen Sie für eine Struktur keinen Standardkonstruktor bereit.
Wenn eine Struktur beim Erstellen von Arrays der Struktur einen Standardkonstruktor definiert, führt die Common Language Runtime automatisch den Standardkonstruktor für jedes Arrayelement aus.
Einige Compiler, z. B. der C#-Compiler, lassen Standardkonstruktoren für Strukturen nicht zu.
Implementieren Sie für Werttypen System.IEquatable'1.
Um zu bestimmen, ob zwei Werttypen gleich sind, ist IEquatable<T> besser geeignet als Equals. Durch die Verwendung der Schnittstelle vermeidet der Aufrufer die negativen Auswirkungen von Boxing und verwalteter Reflektion auf die Leistung.
Stellen Sie sicher, dass ein Zustand, in dem alle Instanzdaten auf 0 (null), false bzw. NULL festgelegt sind, gültig ist.
Durch Befolgen dieser Richtlinie bleiben die neu erstellten Werttypinstanzen nicht in einem unbrauchbaren Zustand. Beispielsweise wurde die folgende Struktur falsch entworfen. Der parametrisierte Konstruktor soll einen gültigen Zustand sicherstellen, doch der Konstruktor wird nicht ausgeführt, wenn ein Array der Struktur erstellt wird. Daher wird das Instanzfeld label mit null (Nothing in Visual Basic) initialisiert. Dies ist für die Implementierung von ToString dieser Struktur nicht gültig.
Public Structure BadStructure
Private label As String
Private width As Integer
Private length As Integer
Public Sub New(ByVal labelValue As String, ByVal widthValue As Integer, ByVal lengthValue As Integer)
If ((labelValue = Nothing) _
OrElse (labelValue.Length = 0)) Then
Throw New ArgumentNullException("label")
End If
label = labelValue
width = widthValue
length = lengthValue
End Sub
Public Overrides Function ToString() As String
' Accessing label.Length throws a NullReferenceException
' when label is null.
Return String.Format("Label length: {0} Label: {1} Width: {2} Length: {3}", label.Length, label, width, length)
End Function
End Structure
public struct BadStructure
{
string label;
int width;
int length;
public BadStructure (string labelValue, int widthValue, int lengthValue)
{
if (labelValue == null || labelValue.Length ==0)
{
throw new ArgumentNullException("label");
}
label = labelValue;
width = widthValue;
length = lengthValue;
}
public override string ToString()
{
// Accessing label.Length throws a NullReferenceException
// when label is null.
return String.Format("Label length: {0} Label: {1} Width: {2} Length: {3}",
label.Length, label, width,length);
}
}
Im folgenden Codebeispiel erfolgt der Entwurf von GoodStructure ohne Prämissen über den Zustand des label-Felds. Der Zweck der ToString-Methode ist die Behandlung einer null-Bezeichnung.
Public Structure GoodStructure
Private label As String
Private width As Integer
Private length As Integer
Public Sub New(ByVal labelValue As String, ByVal widthValue As Integer, ByVal lengthValue As Integer)
label = labelValue
width = widthValue
length = lengthValue
End Sub
Public Overrides Function ToString() As String
' Handle the case where label might be
' initialized to null;
Dim formattedLabel As String = label
Dim formattedLableLength As Integer
If (formattedLabel = Nothing) Then
formattedLabel = "<no label value specified>"
formattedLableLength = 0
Else
formattedLableLength = label.Length
End If
Return String.Format("Label Length: {0} Label: {1} Width: {2} Length: {3}", formattedLableLength, formattedLabel, width, length)
End Function
End Structure
public struct GoodStructure
{
string label;
int width;
int length;
public GoodStructure (string labelValue, int widthValue, int lengthValue)
{
label = labelValue;
width = widthValue;
length = lengthValue;
}
public override string ToString()
{
// Handle the case where label might be
// initialized to null;
string formattedLabel = label;
int formattedLableLength;
if (formattedLabel == null)
{
formattedLabel = "<no label value specified>";
formattedLableLength = 0;
} else
{
formattedLableLength = label.Length;
}
return String.Format("Label Length: {0} Label: {1} Width: {2} Length: {3}",
formattedLableLength, formattedLabel, width, length);
}
}
Erweitern Sie System.ValueType nicht explizit.
Einige Compiler lassen das Erweitern von ValueType nicht zu.
Copyright für einzelne Teile 2005 Microsoft Corporation. Alle Rechte vorbehalten.
Copyright für einzelne Teile Addison-Wesley Corporation. Alle Rechte vorbehalten.
Weitere Informationen zu Entwurfsrichtlinien finden Sie im Buch "Framework Design Guidelines: Conventions, Idioms, and Patterns for Reusable .NET Libraries" von Krzysztof Cwalina und Brad Abrams, veröffentlicht von Addison-Wesley, 2005.
Siehe auch
Konzepte
Auswählen zwischen Klassen und Strukturen