Поделиться через


Разработка структуры

Структуры имеют тип значения. Они размещаются на стеке или в области данных и становятся недоступны, когда выходят из области видимости. В общем случае тип значения эффективен для размещения и освобождения, однако если он используется в сценарии, который требует значительного количества преобразований упаковки-распаковки, этот тип работает хуже по сравнению со ссылочным типом. Дополнительные сведения см. в разделе Упаковка-преобразование и распаковка-преобразование (Руководство по программированию на 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 года.

См. также

Основные понятия

Выбор между классами и структурами

Другие ресурсы

Правила разработки типов

Руководство по разработке библиотек классов