EstructurasStructs

Los structs son similares a las clases que representan las estructuras de datos que pueden contener miembros de datos y miembros de función.Structs are similar to classes in that they represent data structures that can contain data members and function members. Sin embargo, a diferencia de las clases, structs son tipos de valor y no requieren asignación del montón.However, unlike classes, structs are value types and do not require heap allocation. Una variable de un tipo de estructura contiene directamente los datos de la estructura, mientras que una variable de un tipo de clase contiene una referencia a los datos, que se conoce como un objeto.A variable of a struct type directly contains the data of the struct, whereas a variable of a class type contains a reference to the data, the latter known as an object.

Los structs son particularmente útiles para estructuras de datos pequeñas que tengan semánticas de valor.Structs are particularly useful for small data structures that have value semantics. Los números complejos, los puntos de un sistema de coordenadas o los pares clave-valor de un diccionario son buenos ejemplos de structs.Complex numbers, points in a coordinate system, or key-value pairs in a dictionary are all good examples of structs. Clave de estas estructuras de datos es que tienen pocos miembros de datos, que no requieren el uso de herencia o identidad referencial, y que pueden ser implementadas convenientemente utilizando la semántica de valor donde la asignación copia el valor en lugar de la referencia.Key to these data structures is that they have few data members, that they do not require use of inheritance or referential identity, and that they can be conveniently implemented using value semantics where assignment copies the value instead of the reference.

Como se describe en tipos simples, los tipos simples que proporciona C#, tales como int, double, y bool, son en realidad todos los tipos de struct.As described in Simple types, the simple types provided by C#, such as int, double, and bool, are in fact all struct types. Como estos tipos predefinidos son estructuras, también es posible utilizar estructuras y sobrecarga de operadores para implementar nuevos tipos "primitivos" en el lenguaje C#.Just as these predefined types are structs, it is also possible to use structs and operator overloading to implement new "primitive" types in the C# language. Se proporcionan dos ejemplos de estos tipos al final de este capítulo (ejemplos de estructuras).Two examples of such types are given at the end of this chapter (Struct examples).

Declaraciones de estructuraStruct declarations

Un struct_declaration es un type_declaration (declaraciones de tipo) que declara una nueva estructura:A struct_declaration is a type_declaration (Type declarations) that declares a new struct:

struct_declaration
    : attributes? struct_modifier* 'partial'? 'struct' identifier type_parameter_list?
      struct_interfaces? type_parameter_constraints_clause* struct_body ';'?
    ;

Un struct_declaration consta de un conjunto opcional de atributos (atributos), seguido de un conjunto opcional de struct_modifiers (Struct modificadores), seguido de un elemento opcional partial modificador, seguido por la palabra clave struct y un identificador que denomina el struct, seguido por un opcional type_parameter_list especificación (parámetros de tipo), seguido de un elemento opcional struct_interfaces especificación (Modificador parcial)), seguido de un elemento opcional type_parameter_constraints_clauseespecificación s (restricciones de parámetro de tipo), seguido de un struct_body (cuerpo Struct), seguido opcionalmente de un punto y coma.A struct_declaration consists of an optional set of attributes (Attributes), followed by an optional set of struct_modifiers (Struct modifiers), followed by an optional partial modifier, followed by the keyword struct and an identifier that names the struct, followed by an optional type_parameter_list specification (Type parameters), followed by an optional struct_interfaces specification (Partial modifier) ), followed by an optional type_parameter_constraints_clauses specification (Type parameter constraints), followed by a struct_body (Struct body), optionally followed by a semicolon.

Modificadores de estructuraStruct modifiers

Un struct_declaration puede incluir opcionalmente una secuencia de modificadores de estructura:A struct_declaration may optionally include a sequence of struct modifiers:

struct_modifier
    : 'new'
    | 'public'
    | 'protected'
    | 'internal'
    | 'private'
    | struct_modifier_unsafe
    ;

Es un error en tiempo de compilación para el mismo modificador aparezca varias veces en una declaración de struct.It is a compile-time error for the same modifier to appear multiple times in a struct declaration.

Los modificadores de una declaración de estructura tienen el mismo significado que los de una declaración de clase (declaraciones de clase).The modifiers of a struct declaration have the same meaning as those of a class declaration (Class declarations).

Modificador parcialPartial modifier

El partial modificador indica que esto struct_declaration es una declaración de tipo parcial.The partial modifier indicates that this struct_declaration is a partial type declaration. Varias declaraciones de estructura parcial con el mismo nombre dentro de una declaración de espacio de nombres o tipo envolvente se combinan para formar una declaración de struct, siguiendo las reglas especificadas en tipos parciales.Multiple partial struct declarations with the same name within an enclosing namespace or type declaration combine to form one struct declaration, following the rules specified in Partial types.

Interfaces de structStruct interfaces

Puede incluir una declaración de struct un struct_interfaces especificación, en cuyo caso el struct se dice implementar directamente los tipos de interfaz determinado.A struct declaration may include a struct_interfaces specification, in which case the struct is said to directly implement the given interface types.

struct_interfaces
    : ':' interface_type_list
    ;

Implementaciones de interfaz se tratan con más detalle en implementaciones de interfaz.Interface implementations are discussed further in Interface implementations.

Cuerpo de estructuraStruct body

El struct_body de una estructura define los miembros de struct.The struct_body of a struct defines the members of the struct.

struct_body
    : '{' struct_member_declaration* '}'
    ;

Miembros de estructuraStruct members

Los miembros de un struct se componen de los miembros introducidos por su struct_member_declarations y los miembros heredan del tipo System.ValueType.The members of a struct consist of the members introduced by its struct_member_declarations and the members inherited from the type System.ValueType.

struct_member_declaration
    : constant_declaration
    | field_declaration
    | method_declaration
    | property_declaration
    | event_declaration
    | indexer_declaration
    | operator_declaration
    | constructor_declaration
    | static_constructor_declaration
    | type_declaration
    | struct_member_declaration_unsafe
    ;

Salvo por las diferencias que anotó en diferencias entre clase y estructura, las descripciones de los miembros de clase proporcionado en los miembros de clase a través de iteradores se aplican a struct miembros también.Except for the differences noted in Class and struct differences, the descriptions of class members provided in Class members through Iterators apply to struct members as well.

Diferencias entre clase y estructuraClass and struct differences

Structs difieren de las clases en varios aspectos importantes:Structs differ from classes in several important ways:

  • Los structs son tipos de valor (semántica de valores).Structs are value types (Value semantics).
  • Todos los tipos de struct se heredan implícitamente de la clase System.ValueType (herencia).All struct types implicitly inherit from the class System.ValueType (Inheritance).
  • La asignación a una variable de un tipo de estructura crea una copia del valor asignado (asignación).Assignment to a variable of a struct type creates a copy of the value being assigned (Assignment).
  • El valor predeterminado de un struct es el valor generado al establecer todos los campos de tipo de valor en sus valores predeterminados y referencia de todos los campos de tipo a null (los valores predeterminados).The default value of a struct is the value produced by setting all value type fields to their default value and all reference type fields to null (Default values).
  • Operaciones de conversión boxing y unboxing se utilizan para convertir entre un tipo struct y object (conversiones Boxing y unboxing).Boxing and unboxing operations are used to convert between a struct type and object (Boxing and unboxing).
  • El significado de this es diferente para los structs (este acceso).The meaning of this is different for structs (This access).
  • Las declaraciones de campo de instancia para una estructura no pueden incluir inicializadores de variables (inicializadores de campo).Instance field declarations for a struct are not permitted to include variable initializers (Field initializers).
  • Un struct no puede declarar un constructor de instancia sin parámetros (constructores).A struct is not permitted to declare a parameterless instance constructor (Constructors).
  • Un struct no puede declarar un destructor (destructores).A struct is not permitted to declare a destructor (Destructors).

Semántica de valoresValue semantics

Los structs son tipos de valor (los tipos de valor) y se dice que tienen semántica de valores.Structs are value types (Value types) and are said to have value semantics. Las clases, por otro lado, son tipos de referencia (hacen referencia a tipos) y se dice que tienen semántica de referencia.Classes, on the other hand, are reference types (Reference types) and are said to have reference semantics.

Una variable de un tipo de estructura contiene directamente los datos de la estructura, mientras que una variable de un tipo de clase contiene una referencia a los datos, que se conoce como un objeto.A variable of a struct type directly contains the data of the struct, whereas a variable of a class type contains a reference to the data, the latter known as an object. Cuando un struct B contiene un campo de instancia del tipo A y A es un tipo struct, es un error de tiempo de compilación de A depender B o un tipo construido a partir de B.When a struct B contains an instance field of type A and A is a struct type, it is a compile-time error for A to depend on B or a type constructed from B. Un struct X depende directamente de un struct Y si X contiene un campo de instancia del tipo Y.A struct X directly depends on a struct Y if X contains an instance field of type Y. Dada esta definición, el conjunto completo de las estructuras de los que depende un struct es el cierre transitivo de los depende directamente relación.Given this definition, the complete set of structs upon which a struct depends is the transitive closure of the directly depends on relationship. Por ejemploFor example

struct Node
{
    int data;
    Node next; // error, Node directly depends on itself
}

es un error porque Node contiene un campo de instancia de su propio tipo.is an error because Node contains an instance field of its own type. Otro ejemploAnother example

struct A { B b; }

struct B { C c; }

struct C { A a; }

es un error porque cada uno de los tipos A, B, y C dependen entre sí.is an error because each of the types A, B, and C depend on each other.

Con las clases, es posible que dos variables hagan referencia al mismo objeto y, por tanto, las operaciones en una variable afecten al objeto al que hace referencia la otra variable.With classes, it is possible for two variables to reference the same object, and thus possible for operations on one variable to affect the object referenced by the other variable. Estructuras, cada variable tiene su propia copia de los datos (excepto en el caso de ref y out las variables de parámetro), y no es posible que las operaciones en una variable afecten a la otra.With structs, the variables each have their own copy of the data (except in the case of ref and out parameter variables), and it is not possible for operations on one to affect the other. Además, dado que las estructuras no son tipos de referencia, no es posible para los valores de un tipo struct sea null.Furthermore, because structs are not reference types, it is not possible for values of a struct type to be null.

Dada la declaraciónGiven the declaration

struct Point
{
    public int x, y;

    public Point(int x, int y) {
        this.x = x;
        this.y = y;
    }
}

el fragmento de códigothe code fragment

Point a = new Point(10, 10);
Point b = a;
a.x = 100;
System.Console.WriteLine(b.x);

presenta el valor 10.outputs the value 10. La asignación de a a b crea una copia del valor, y b , por tanto, no se ve afectado por la asignación a a.x.The assignment of a to b creates a copy of the value, and b is thus unaffected by the assignment to a.x. Tenía Point en su lugar se ha sido declarado como una clase, el resultado sería 100 porque a y b haría referencia al mismo objeto.Had Point instead been declared as a class, the output would be 100 because a and b would reference the same object.

HerenciaInheritance

Todos los tipos de struct se heredan implícitamente de la clase System.ValueType, que, a su vez, hereda de la clase object.All struct types implicitly inherit from the class System.ValueType, which, in turn, inherits from class object. Una declaración de estructura puede especificar una lista de interfaces implementadas, pero no es posible que una declaración de estructura especificar una clase base.A struct declaration may specify a list of implemented interfaces, but it is not possible for a struct declaration to specify a base class.

Tipos de estructura nunca son abstractos y son siempre sellados implícitamente.Struct types are never abstract and are always implicitly sealed. El abstract y sealed modificadores, por tanto, no se permiten en una declaración de struct.The abstract and sealed modifiers are therefore not permitted in a struct declaration.

Puesto que no se admite la herencia para los structs, la accesibilidad declarada de un miembro de estructura no puede ser protected o protected internal.Since inheritance isn't supported for structs, the declared accessibility of a struct member cannot be protected or protected internal.

Miembros de función en un struct no pueden ser abstract o virtualy el override modificador sólo se permite para invalidar métodos heredados de System.ValueType.Function members in a struct cannot be abstract or virtual, and the override modifier is allowed only to override methods inherited from System.ValueType.

AsignaciónAssignment

La asignación a una variable de un tipo de estructura crea una copia del valor asignado.Assignment to a variable of a struct type creates a copy of the value being assigned. Esto difiere de la asignación a una variable de un tipo de clase, que copia la referencia pero no el objeto identificado por la referencia.This differs from assignment to a variable of a class type, which copies the reference but not the object identified by the reference.

Al igual que una asignación, cuando un struct se pasa como un parámetro de valor o se devuelve como resultado de un miembro de función, se crea una copia de la estructura.Similar to an assignment, when a struct is passed as a value parameter or returned as the result of a function member, a copy of the struct is created. Un struct puede pasarse por referencia a un miembro de función con un ref o out parámetro.A struct may be passed by reference to a function member using a ref or out parameter.

Cuando una propiedad o indizador de una estructura es el destino de una asignación, la expresión de instancia asociada con el acceso de propiedad o indizador debe estar clasificada como una variable.When a property or indexer of a struct is the target of an assignment, the instance expression associated with the property or indexer access must be classified as a variable. Si la expresión de instancia se clasifica como un valor, se produce un error en tiempo de compilación.If the instance expression is classified as a value, a compile-time error occurs. Esto se describe con más detalle en asignación Simple.This is described in further detail in Simple assignment.

Valores predeterminadosDefault values

Como se describe en los valores predeterminados, varios tipos de variables se inicializan automáticamente en su valor predeterminado cuando se crean.As described in Default values, several kinds of variables are automatically initialized to their default value when they are created. Para las variables de tipos de clase y otros tipos de referencia, este valor predeterminado es null.For variables of class types and other reference types, this default value is null. Sin embargo, dado que los structs son tipos de valor no pueden ser null, el valor predeterminado de un struct es el valor generado al establecer todos los campos de tipo de valor en sus valores predeterminados y referencia de todos los campos de tipo a null.However, since structs are value types that cannot be null, the default value of a struct is the value produced by setting all value type fields to their default value and all reference type fields to null.

Que hace referencia a la Point estructura declarada anteriormente, en el ejemploReferring to the Point struct declared above, the example

Point[] a = new Point[100];

Inicializa cada Point en la matriz en el valor generado al establecer el x y y campos en cero.initializes each Point in the array to the value produced by setting the x and y fields to zero.

El valor predeterminado de un struct se corresponde con el valor devuelto por el constructor predeterminado del struct (constructores predeterminados).The default value of a struct corresponds to the value returned by the default constructor of the struct (Default constructors). A diferencia de una clase, un struct no se permite declarar un constructor de instancia sin parámetros.Unlike a class, a struct is not permitted to declare a parameterless instance constructor. En su lugar, cada estructura tiene implícitamente un constructor de instancia sin parámetros que siempre devuelve el valor que es el resultado de establecer todos los campos de tipo de valor a sus valores predeterminados y referencia de todos los campos de tipo a null.Instead, every struct implicitly has a parameterless instance constructor which always returns the value that results from setting all value type fields to their default value and all reference type fields to null.

Las estructuras deben diseñarse a tener en cuenta el estado de inicialización predeterminado con un estado válido.Structs should be designed to consider the default initialization state a valid state. En el ejemploIn the example

using System;

struct KeyValuePair
{
    string key;
    string value;

    public KeyValuePair(string key, string value) {
        if (key == null || value == null) throw new ArgumentException();
        this.key = key;
        this.value = value;
    }
}

el constructor de instancia definido por el usuario protege contra los valores null solo cuando es llamado explícitamente.the user-defined instance constructor protects against null values only where it is explicitly called. En casos donde un KeyValuePair variable está sujeta a la inicialización de un valor predeterminado, el key y value campos será nulos y la estructura debe estar preparada para controlar este estado.In cases where a KeyValuePair variable is subject to default value initialization, the key and value fields will be null, and the struct must be prepared to handle this state.

Conversión boxing y conversión unboxingBoxing and unboxing

Un valor de un tipo de clase se puede convertir al tipo object o a un tipo de interfaz que es implementado por la clase simplemente tratando la referencia como otro tipo en tiempo de compilación.A value of a class type can be converted to type object or to an interface type that is implemented by the class simply by treating the reference as another type at compile-time. Del mismo modo, un valor de tipo object o un valor de un tipo de interfaz se puede convertir a un tipo de clase sin cambiar la referencia (pero evidentemente una comprobación de tipo de tiempo de ejecución es necesaria en este caso).Likewise, a value of type object or a value of an interface type can be converted back to a class type without changing the reference (but of course a run-time type check is required in this case).

Dado que las estructuras no son tipos de referencia, estas operaciones se implementan de forma diferente para tipos de estructura.Since structs are not reference types, these operations are implemented differently for struct types. Cuando un valor de un tipo de estructura se convierte al tipo object o a un tipo de interfaz implementada por la estructura, realiza una operación de conversión boxing.When a value of a struct type is converted to type object or to an interface type that is implemented by the struct, a boxing operation takes place. Del mismo modo, cuando un valor de tipo object o un valor de un tipo de interfaz se convierte a un tipo de estructura, realiza una operación de conversión unboxing.Likewise, when a value of type object or a value of an interface type is converted back to a struct type, an unboxing operation takes place. Una diferencia fundamental con respecto a las mismas operaciones en tipos de clase es que conversión boxing y unboxing copian el valor de struct, ya sea dentro o fuera de la instancia de la conversión boxing.A key difference from the same operations on class types is that boxing and unboxing copies the struct value either into or out of the boxed instance. Por lo tanto, después de una operación de conversión boxing o conversión unboxing, los cambios realizados en la estructura de conversión unboxing no se reflejan en la estructura de conversión boxing.Thus, following a boxing or unboxing operation, changes made to the unboxed struct are not reflected in the boxed struct.

Cuando un tipo struct invalida un método virtual heredado de System.Object (como Equals, GetHashCode, o ToString), la invocación del método virtual a través de una instancia del tipo struct no provoca la conversión boxing se producen.When a struct type overrides a virtual method inherited from System.Object (such as Equals, GetHashCode, or ToString), invocation of the virtual method through an instance of the struct type does not cause boxing to occur. Esto es cierto incluso cuando se utiliza la estructura como un parámetro de tipo y la invocación se produce a través de una instancia del tipo de parámetro de tipo.This is true even when the struct is used as a type parameter and the invocation occurs through an instance of the type parameter type. Por ejemplo:For example:

using System;

struct Counter
{
    int value;

    public override string ToString() {
        value++;
        return value.ToString();
    }
}

class Program
{
    static void Test<T>() where T: new() {
        T x = new T();
        Console.WriteLine(x.ToString());
        Console.WriteLine(x.ToString());
        Console.WriteLine(x.ToString());
    }

    static void Main() {
        Test<Counter>();
    }
}

La salida del programa es:The output of the program is:

1
2
3

Aunque es poco recomendable ToString para tener efectos secundarios, el ejemplo se muestra que se ha producido ninguna conversión boxing para las tres invocaciones de x.ToString().Although it is bad style for ToString to have side effects, the example demonstrates that no boxing occurred for the three invocations of x.ToString().

De forma similar, la conversión boxing implícitamente nunca se produce cuando el acceso a un miembro en un parámetro de tipo restringido.Similarly, boxing never implicitly occurs when accessing a member on a constrained type parameter. Por ejemplo, supongamos que una interfaz ICounter contiene un método Increment que puede usarse para modificar un valor.For example, suppose an interface ICounter contains a method Increment which can be used to modify a value. Si ICounter se utiliza como una restricción, la implementación de la Increment se llama al método con una referencia a la variable que Increment se llamó en nunca una copia con conversión boxing.If ICounter is used as a constraint, the implementation of the Increment method is called with a reference to the variable that Increment was called on, never a boxed copy.

using System;

interface ICounter
{
    void Increment();
}

struct Counter: ICounter
{
    int value;

    public override string ToString() {
        return value.ToString();
    }

    void ICounter.Increment() {
        value++;
    }
}

class Program
{
    static void Test<T>() where T: ICounter, new() {
        T x = new T();
        Console.WriteLine(x);
        x.Increment();                    // Modify x
        Console.WriteLine(x);
        ((ICounter)x).Increment();        // Modify boxed copy of x
        Console.WriteLine(x);
    }

    static void Main() {
        Test<Counter>();
    }
}

La primera llamada a Increment modifica el valor en la variable x.The first call to Increment modifies the value in the variable x. Esto no es equivalente a la segunda llamada a Increment, que modifica el valor de una copia encuadrada de x.This is not equivalent to the second call to Increment, which modifies the value in a boxed copy of x. Por lo tanto, la salida del programa es:Thus, the output of the program is:

0
1
1

Para obtener más información sobre las conversiones boxing y unboxing, consulte conversiones Boxing y unboxing.For further details on boxing and unboxing, see Boxing and unboxing.

Significado de estoMeaning of this

Dentro de un constructor de instancia o un miembro de función de la instancia de una clase, this se clasifica como un valor.Within an instance constructor or instance function member of a class, this is classified as a value. Por lo tanto, mientras this puede usarse para hacer referencia a la instancia para que se invoca el miembro de función, no es posible asignar a this en un miembro de función de una clase.Thus, while this can be used to refer to the instance for which the function member was invoked, it is not possible to assign to this in a function member of a class.

Dentro de un constructor de instancia de un struct, this corresponde a un out parámetro del tipo struct y dentro de un miembro de función de la instancia de un struct, this corresponde a un ref parámetro del tipo struct.Within an instance constructor of a struct, this corresponds to an out parameter of the struct type, and within an instance function member of a struct, this corresponds to a ref parameter of the struct type. En ambos casos, this se clasifica como una variable, y es posible modificar el struct completo para el que el miembro de función se invocó mediante la asignación a this o si se pasa como un ref o out parámetro.In both cases, this is classified as a variable, and it is possible to modify the entire struct for which the function member was invoked by assigning to this or by passing this as a ref or out parameter.

Inicializadores de campoField initializers

Como se describe en los valores predeterminados, el valor predeterminado de una estructura formada por el valor que es el resultado de establecer todos los campos de tipo de valor a sus valores predeterminados y referencia de todos los campos de tipo a null.As described in Default values, the default value of a struct consists of the value that results from setting all value type fields to their default value and all reference type fields to null. Por este motivo, un struct no permite que las declaraciones de campo de instancia para incluir a inicializadores de variables.For this reason, a struct does not permit instance field declarations to include variable initializers. Esta restricción se aplica solo a los campos de instancia.This restriction applies only to instance fields. Los campos estáticos de una estructura pueden incluir a inicializadores de variables.Static fields of a struct are permitted to include variable initializers.

El ejemploThe example

struct Point
{
    public int x = 1;  // Error, initializer not permitted
    public int y = 1;  // Error, initializer not permitted
}

es un error porque las declaraciones de campo de instancia incluyen a inicializadores de variables.is in error because the instance field declarations include variable initializers.

ConstructoresConstructors

A diferencia de una clase, un struct no se permite declarar un constructor de instancia sin parámetros.Unlike a class, a struct is not permitted to declare a parameterless instance constructor. En su lugar, cada estructura tiene implícitamente un constructor de instancia sin parámetros que siempre devuelve el valor que se obtiene al establecer todos los campos de tipo de valor a sus valores predeterminados y referencia de todos los campos de tipo null (constructorespredeterminados).Instead, every struct implicitly has a parameterless instance constructor which always returns the value that results from setting all value type fields to their default value and all reference type fields to null (Default constructors). Un struct puede declarar constructores de instancia con parámetros.A struct can declare instance constructors having parameters. Por ejemploFor example

struct Point
{
    int x, y;

    public Point(int x, int y) {
        this.x = x;
        this.y = y;
    }
}

Dada la declaración anterior, las instruccionesGiven the above declaration, the statements

Point p1 = new Point();
Point p2 = new Point(0, 0);

ambos crean un Point con x y y inicializadas en cero.both create a Point with x and y initialized to zero.

Un constructor de instancia de struct no puede incluir un inicializador de constructor del formulario base(...).A struct instance constructor is not permitted to include a constructor initializer of the form base(...).

Si el constructor de instancia de struct no especifica un inicializador de constructor, el this variable corresponde a un out parámetro de tipo de estructura y otros similares a un out parámetro, this debe asignarlo definitivamente () Asignación definitiva) en todas las ubicaciones donde se devuelve el constructor.If the struct instance constructor doesn't specify a constructor initializer, the this variable corresponds to an out parameter of the struct type, and similar to an out parameter, this must be definitely assigned (Definite assignment) at every location where the constructor returns. Si el constructor de instancia de struct especifica un inicializador de constructor, el this variable corresponde a un ref parámetro de tipo de estructura y otros similares a un ref parámetro, this se considera asignado definitivamente en entrada en el cuerpo del constructor.If the struct instance constructor specifies a constructor initializer, the this variable corresponds to a ref parameter of the struct type, and similar to a ref parameter, this is considered definitely assigned on entry to the constructor body. Tenga en cuenta la siguiente implementación de constructor de instancia:Consider the instance constructor implementation below:

struct Point
{
    int x, y;

    public int X {
        set { x = value; }
    }

    public int Y {
        set { y = value; }
    }

    public Point(int x, int y) {
        X = x;        // error, this is not yet definitely assigned
        Y = y;        // error, this is not yet definitely assigned
    }
}

Ninguna función miembro de instancia (incluidos los descriptores de acceso set de las propiedades X y Y) se puede llamar hasta que se han asignado definitivamente todos los campos de la estructura que se está construyendo.No instance member function (including the set accessors for the properties X and Y) can be called until all fields of the struct being constructed have been definitely assigned. La única excepción implica las propiedades implementadas automáticamente (implementa automáticamente propiedades).The only exception involves automatically implemented properties (Automatically implemented properties). Las reglas de asignación definitiva (expresiones de asignación Simple) excluir específicamente la asignación a una propiedad automática de un tipo de estructura dentro de un constructor de instancia de ese tipo de struct: esta asignación se considera un definitiva asignación del campo oculto de respaldo de la propiedad automática.The definite assignment rules (Simple assignment expressions) specifically exempt assignment to an auto-property of a struct type within an instance constructor of that struct type: such an assignment is considered a definite assignment of the hidden backing field of the auto-property. Por lo tanto, se permite lo siguiente:Thus, the following is allowed:

struct Point
{
    public int X { get; set; }
    public int Y { get; set; }

    public Point(int x, int y) {
        X = x;      // allowed, definitely assigns backing field
        Y = y;      // allowed, definitely assigns backing field
    }

DestructoresDestructors

Un struct no se permite declarar un destructor.A struct is not permitted to declare a destructor.

Constructores estáticosStatic constructors

Los constructores estáticos para las estructuras siguen la mayoría de las mismas reglas que las clases.Static constructors for structs follow most of the same rules as for classes. El primero de los siguientes eventos que se producen dentro de un dominio de aplicación, se desencadena la ejecución de un constructor estático para un tipo struct:The execution of a static constructor for a struct type is triggered by the first of the following events to occur within an application domain:

  • Se hace referencia a un miembro estático del tipo struct.A static member of the struct type is referenced.
  • Se llama a un constructor declarado explícitamente del tipo struct.An explicitly declared constructor of the struct type is called.

La creación de los valores predeterminados (los valores predeterminados) tipos de struct no desencadena el constructor estático.The creation of default values (Default values) of struct types does not trigger the static constructor. (Un ejemplo de esto es el valor inicial de elementos de matriz).(An example of this is the initial value of elements in an array.)

Ejemplos de estructurasStruct examples

Lo siguiente muestra dos ejemplos importantes de usar struct tipos para crear tipos que pueden usarse de forma similar a los tipos predefinidos del lenguaje, pero con semántica modificada.The following shows two significant examples of using struct types to create types that can be used similarly to the predefined types of the language, but with modified semantics.

Tipo de entero de base de datosDatabase integer type

El DBInt estructura siguiente implementa un tipo entero que puede representar el conjunto completo de valores de la int tipo, además de un estado adicional que indica un valor desconocido.The DBInt struct below implements an integer type that can represent the complete set of values of the int type, plus an additional state that indicates an unknown value. Un tipo con estas características se usa habitualmente en las bases de datos.A type with these characteristics is commonly used in databases.

using System;

public struct DBInt
{
    // The Null member represents an unknown DBInt value.

    public static readonly DBInt Null = new DBInt();

    // When the defined field is true, this DBInt represents a known value
    // which is stored in the value field. When the defined field is false,
    // this DBInt represents an unknown value, and the value field is 0.

    int value;
    bool defined;

    // Private instance constructor. Creates a DBInt with a known value.

    DBInt(int value) {
        this.value = value;
        this.defined = true;
    }

    // The IsNull property is true if this DBInt represents an unknown value.

    public bool IsNull { get { return !defined; } }

    // The Value property is the known value of this DBInt, or 0 if this
    // DBInt represents an unknown value.

    public int Value { get { return value; } }

    // Implicit conversion from int to DBInt.

    public static implicit operator DBInt(int x) {
        return new DBInt(x);
    }

    // Explicit conversion from DBInt to int. Throws an exception if the
    // given DBInt represents an unknown value.

    public static explicit operator int(DBInt x) {
        if (!x.defined) throw new InvalidOperationException();
        return x.value;
    }

    public static DBInt operator +(DBInt x) {
        return x;
    }

    public static DBInt operator -(DBInt x) {
        return x.defined ? -x.value : Null;
    }

    public static DBInt operator +(DBInt x, DBInt y) {
        return x.defined && y.defined? x.value + y.value: Null;
    }

    public static DBInt operator -(DBInt x, DBInt y) {
        return x.defined && y.defined? x.value - y.value: Null;
    }

    public static DBInt operator *(DBInt x, DBInt y) {
        return x.defined && y.defined? x.value * y.value: Null;
    }

    public static DBInt operator /(DBInt x, DBInt y) {
        return x.defined && y.defined? x.value / y.value: Null;
    }

    public static DBInt operator %(DBInt x, DBInt y) {
        return x.defined && y.defined? x.value % y.value: Null;
    }

    public static DBBool operator ==(DBInt x, DBInt y) {
        return x.defined && y.defined? x.value == y.value: DBBool.Null;
    }

    public static DBBool operator !=(DBInt x, DBInt y) {
        return x.defined && y.defined? x.value != y.value: DBBool.Null;
    }

    public static DBBool operator >(DBInt x, DBInt y) {
        return x.defined && y.defined? x.value > y.value: DBBool.Null;
    }

    public static DBBool operator <(DBInt x, DBInt y) {
        return x.defined && y.defined? x.value < y.value: DBBool.Null;
    }

    public static DBBool operator >=(DBInt x, DBInt y) {
        return x.defined && y.defined? x.value >= y.value: DBBool.Null;
    }

    public static DBBool operator <=(DBInt x, DBInt y) {
        return x.defined && y.defined? x.value <= y.value: DBBool.Null;
    }

    public override bool Equals(object obj) {
        if (!(obj is DBInt)) return false;
        DBInt x = (DBInt)obj;
        return value == x.value && defined == x.defined;
    }

    public override int GetHashCode() {
        return value;
    }

    public override string ToString() {
        return defined? value.ToString(): "DBInt.Null";
    }
}

Tipo booleano de la base de datosDatabase boolean type

El DBBool estructura siguiente implementa un tipo lógico de tres valores.The DBBool struct below implements a three-valued logical type. Los valores posibles de este tipo son DBBool.True, DBBool.False, y DBBool.Null, donde el Null miembro indica un valor desconocido.The possible values of this type are DBBool.True, DBBool.False, and DBBool.Null, where the Null member indicates an unknown value. Estos tipos lógicos de tres valores se usan habitualmente en las bases de datos.Such three-valued logical types are commonly used in databases.

using System;

public struct DBBool
{
    // The three possible DBBool values.

    public static readonly DBBool Null = new DBBool(0);
    public static readonly DBBool False = new DBBool(-1);
    public static readonly DBBool True = new DBBool(1);

    // Private field that stores -1, 0, 1 for False, Null, True.

    sbyte value;

    // Private instance constructor. The value parameter must be -1, 0, or 1.

    DBBool(int value) {
        this.value = (sbyte)value;
    }

    // Properties to examine the value of a DBBool. Return true if this
    // DBBool has the given value, false otherwise.

    public bool IsNull { get { return value == 0; } }

    public bool IsFalse { get { return value < 0; } }

    public bool IsTrue { get { return value > 0; } }

    // Implicit conversion from bool to DBBool. Maps true to DBBool.True and
    // false to DBBool.False.

    public static implicit operator DBBool(bool x) {
        return x? True: False;
    }

    // Explicit conversion from DBBool to bool. Throws an exception if the
    // given DBBool is Null, otherwise returns true or false.

    public static explicit operator bool(DBBool x) {
        if (x.value == 0) throw new InvalidOperationException();
        return x.value > 0;
    }

    // Equality operator. Returns Null if either operand is Null, otherwise
    // returns True or False.

    public static DBBool operator ==(DBBool x, DBBool y) {
        if (x.value == 0 || y.value == 0) return Null;
        return x.value == y.value? True: False;
    }

    // Inequality operator. Returns Null if either operand is Null, otherwise
    // returns True or False.

    public static DBBool operator !=(DBBool x, DBBool y) {
        if (x.value == 0 || y.value == 0) return Null;
        return x.value != y.value? True: False;
    }

    // Logical negation operator. Returns True if the operand is False, Null
    // if the operand is Null, or False if the operand is True.

    public static DBBool operator !(DBBool x) {
        return new DBBool(-x.value);
    }

    // Logical AND operator. Returns False if either operand is False,
    // otherwise Null if either operand is Null, otherwise True.

    public static DBBool operator &(DBBool x, DBBool y) {
        return new DBBool(x.value < y.value? x.value: y.value);
    }

    // Logical OR operator. Returns True if either operand is True, otherwise
    // Null if either operand is Null, otherwise False.

    public static DBBool operator |(DBBool x, DBBool y) {
        return new DBBool(x.value > y.value? x.value: y.value);
    }

    // Definitely true operator. Returns true if the operand is True, false
    // otherwise.

    public static bool operator true(DBBool x) {
        return x.value > 0;
    }

    // Definitely false operator. Returns true if the operand is False, false
    // otherwise.

    public static bool operator false(DBBool x) {
        return x.value < 0;
    }

    public override bool Equals(object obj) {
        if (!(obj is DBBool)) return false;
        return value == ((DBBool)obj).value;
    }

    public override int GetHashCode() {
        return value;
    }

    public override string ToString() {
        if (value > 0) return "DBBool.True";
        if (value < 0) return "DBBool.False";
        return "DBBool.Null";
    }
}