Compartir a través de


Diseño de estructuras

Actualización: noviembre 2007

Las estructuras son tipos de valor. Se asignan en la pila o en línea y se desasignan cuando salen del ámbito. En general, cuesta menos asignar o desasignar los tipos de valor; sin embargo, si se utilizan en escenarios que requieren una cantidad significativa de conversiones boxing y unboxing, su rendimiento es deficiente en comparación con los tipos de referencia. Para obtener más información, vea Conversión boxing y unboxing (Guía de programación de C#).

Para obtener información adicional sobre los tipos de valor y los tipos de referencia, vea Información general acerca del sistema de tipos común.

No proporcione un constructor predeterminado para una estructura.

Si una estructura define un constructor predeterminado, cuando se crean matrices de la estructura, Common Language Runtime ejecuta automáticamente el constructor predeterminado en cada uno de los elementos de la matriz.

Algunos compiladores, como el compilador de C#, no permiten que las estructuras tengan constructores predeterminados.

Implemente System.IEquatable`1 en los tipos de valor.

Se prefiere utilizar IEquatable<T> frente a Equals para determinar si dos tipos de valor son iguales. Utilizando la interfaz, el llamador evita el impacto negativo en el rendimiento que conlleva la aplicación de la conversión boxing y la reflexión administrada.

Asegúrese de que es válido un estado donde todos los datos de instancia están establecidos en cero, false o null (según corresponda).

Siguiendo esta instrucción, las instancias del tipo de valor construidas desde cero no quedan en un estado inutilizable. Por ejemplo, la estructura siguiente está incorrectamente diseñada. Se supone que el constructor con parámetros garantiza un estado válido, pero no se ejecuta el constructor cuando se crea una matriz de la estructura. Esto significa que el campo de instancia label se inicializa en null (Nothing en Visual Basic), que no es válido para la implementación de esta estructura de 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);
    }
}

En el ejemplo de código siguiente, el diseño de GoodStructure no presupone el estado del campo label. El método ToString está diseñado para controlar una etiqueta 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);
    }
}

No extienda explícitamente System.ValueType.

Algunos compiladores no permiten extender ValueType.

Portions Copyright 2005 Microsoft Corporation. Reservados todos los derechos.

Portions Copyright Addison-Wesley Corporation. Reservados todos los derechos.

Para obtener más información sobre las directrices de diseño, consulte el libro titulado "Framework Design Guidelines: Conventions, Idioms, and Patterns for Reusable .NET Libraries" de Krzysztof Cwalina y Brad Abrams, publicado por Addison-Wesley, 2005.

Vea también

Conceptos

Elegir entre clases y estructuras

Otros recursos

Instrucciones de diseño de tipos

Instrucciones de diseño para desarrollar bibliotecas de clases