Разработка структуры
Структуры имеют тип значения. Они размещаются на стеке или в области данных и становятся недоступны, когда выходят из области видимости. В общем случае тип значения эффективен для размещения и освобождения, однако если он используется в сценарии, который требует значительного количества преобразований упаковки-распаковки, этот тип работает хуже по сравнению со ссылочным типом. Дополнительные сведения см. в разделе Упаковка-преобразование и распаковка-преобразование (Руководство по программированию на C#).
Дополнительные сведения о типах значения и ссылочных типах см. в разделе Система общих типов CTS.
Не предоставляйте конструктор по умолчанию для структуры.
Если в структуре определен конструктор по умолчанию, то при создании массивов структуры среда CLR автоматически вызовет конструктор по умолчанию для каждого элемента массива.
Некоторые компиляторы, такие как компилятор C#, не позволяют структурам иметь конструктор по умолчанию.
Не реализуйте System.IEquatable`1 на типах значения.
IEquatable<T> предпочтительнее, чем Equals для сравнения двух типов значения. При использовании интерфейса предотвращается негативное влияние преобразования упаковки и управляемого отражения.
Обязательно убедитесь, что состояние, в котором все данные экземпляра имеют значения false, null иле нулевые (в зависимости от конкретного случая) является приемлемым.
Если вы будете следовать этому указанию, вновь созданные вами экземпляры типов значения не останутся в неиспользуемом состоянии. Например, следующая структура спроектирована неправильно. Параметризованный конструктор предназначен для обеспечения корректного состояния, но конструктор не выполняется, когда создается массив структур. Это означает, что экземпляр поля label инициализируется в null (Nothing в Visual Basic), что недопустимо для реализации этой структуры для метода ToString.
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);
}
}
В следующем примере программного кода при описании структуры GoodStructure не делается никаких предположений о состоянии поля label. Метод ToString разработан для управления меткой null.
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);
}
}
Не расширяйте явно System.ValueType.
Некоторые компиляторы не позволяют расширять ValueType.
Охраняется авторским правом Copyright 2005 Microsoft Corporation. Все права защищены.
Фрагменты — © Addison-Wesley Corporation. Все права защищены.
Для дополнительной информации о разработке руководящих принципов, смотрите "руководства по разработке рамок: Конвенций, идиомы и шаблоны для повторного использования.NET библиотек"книга, Кшиштоф Cwalina и Брэд Абрамс, опубликованных Addison-Wesley, 2005 года.
См. также
Основные понятия
Выбор между классами и структурами