EstruturasStructs

As estruturas são semelhantes às classes, pois representam estruturas de dados que podem conter membros de dados e membros de função.Structs are similar to classes in that they represent data structures that can contain data members and function members. No entanto, ao contrário das classes, as structs são tipos de valor e não exigem alocação de heap.However, unlike classes, structs are value types and do not require heap allocation. Uma variável de um tipo struct contém diretamente os dados da estrutura, enquanto uma variável de um tipo de classe contém uma referência aos dados, o último conhecido como um 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.

Os structs são particularmente úteis para estruturas de dados pequenas que têm semântica de valor.Structs are particularly useful for small data structures that have value semantics. Números complexos, pontos em um sistema de coordenadas ou pares chave-valor em um dicionário são exemplos de structs.Complex numbers, points in a coordinate system, or key-value pairs in a dictionary are all good examples of structs. A chave para essas estruturas de dados é que elas têm poucos membros de dados, que não exigem o uso de herança ou identidade referencial, e que podem ser convenientemente implementadas usando semântica de valor em que a atribuição copia o valor em vez da referência.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.

Conforme descrito em tipos simples, os tipos simples fornecidos pelo C#, como int , double e bool , são, na verdade, todos os 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. Assim como esses tipos predefinidos são structs, também é possível usar structs e sobrecarga de operador para implementar novos tipos "primitivos" na linguagem 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. Dois exemplos desses tipos são fornecidos no final deste capítulo (exemplos de struct).Two examples of such types are given at the end of this chapter (Struct examples).

Declarações de structStruct declarations

Uma struct_declaration é uma type_declaration (declarações de tipo) que declara uma nova struct: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 ';'?
    ;

Um struct_declaration consiste em um conjunto opcional de atributos (atributos), seguido por um conjunto opcional de struct_modifier s (modificadores de struct), seguido por um partial modificador opcional, seguido pela palavra-chave struct e um identificador que nomeia a struct, seguido por uma especificação opcional de type_parameter_list (parâmetros de tipo), seguido por uma especificação de struct_interfaces opcional (modificador parcial)), seguido por uma especificação opcional de type_parameter_constraints_clause s (restrições de parâmetro de tipo), seguido por um struct_body (corpo de struct), opcionalmente seguido por um ponto eA struct_declaration consists of an optional set of attributes (Attributes), followed by an optional set of struct_modifier s (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_clause s specification (Type parameter constraints), followed by a struct_body (Struct body), optionally followed by a semicolon.

Modificadores de structStruct modifiers

Um struct_declaration pode, opcionalmente, incluir uma sequência de modificadores de struct:A struct_declaration may optionally include a sequence of struct modifiers:

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

É um erro de tempo de compilação para o mesmo modificador aparecer várias vezes em uma declaração de struct.It is a compile-time error for the same modifier to appear multiple times in a struct declaration.

Os modificadores de uma declaração de struct têm o mesmo significado que os de uma declaração de classe (declarações de classe).The modifiers of a struct declaration have the same meaning as those of a class declaration (Class declarations).

Modificador parcialPartial modifier

O partial modificador indica que esse struct_declaration é uma declaração de tipo parcial.The partial modifier indicates that this struct_declaration is a partial type declaration. Várias declarações de struct parciais com o mesmo nome dentro de um namespace delimitador ou declaração de tipo são combinadas para formar uma declaração de struct, seguindo as regras especificadas em tipos parciais.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

Uma declaração de struct pode incluir uma especificação de struct_interfaces ; nesse caso, o struct é dito para implementar diretamente os tipos de interface fornecidos.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
    ;

Implementações de interface são discutidas mais detalhadamente em implementações de interface.Interface implementations are discussed further in Interface implementations.

Corpo da structStruct body

A struct_body de uma struct define os membros da estrutura.The struct_body of a struct defines the members of the struct.

struct_body
    : '{' struct_member_declaration* '}'
    ;

Membros de structStruct members

Os membros de uma struct consistem nos membros introduzidos por seu struct_member_declaration s e os membros herdados do tipo System.ValueType .The members of a struct consist of the members introduced by its struct_member_declaration s 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
    ;

Exceto pelas diferenças observadas nas diferenças de classe e estrutura, as descrições dos membros de classe fornecidos em membros de classe por meio de funções assíncronas também se aplicam a membros de struct.Except for the differences noted in Class and struct differences, the descriptions of class members provided in Class members through Async functions apply to struct members as well.

Diferenças de classe e structClass and struct differences

As estruturas diferem das classes de várias maneiras importantes:Structs differ from classes in several important ways:

  • Structs são tipos de valor (semântica de valor).Structs are value types (Value semantics).
  • Todos os tipos de struct herdam implicitamente da classe System.ValueType (herança).All struct types implicitly inherit from the class System.ValueType (Inheritance).
  • A atribuição a uma variável de um tipo struct cria uma cópia do valor que está sendo atribuído (atribuição).Assignment to a variable of a struct type creates a copy of the value being assigned (Assignment).
  • O valor padrão de uma struct é o valor produzido pela configuração de todos os campos de tipo de valor para seu valor padrão e todos os campos de tipo de referência como null (valores padrão).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).
  • As operações boxing e unboxing são usadas para converter entre um tipo struct e object (boxing e unboxing).Boxing and unboxing operations are used to convert between a struct type and object (Boxing and unboxing).
  • O significado de this é diferente para structs (esse acesso).The meaning of this is different for structs (This access).
  • As declarações de campo de instância para um struct não têm permissão para incluir inicializadores de variável (inicializadores de campo).Instance field declarations for a struct are not permitted to include variable initializers (Field initializers).
  • Um struct não tem permissão para declarar um construtor de instância sem parâmetros (construtores).A struct is not permitted to declare a parameterless instance constructor (Constructors).
  • Uma struct não tem permissão para declarar um destruidor (destruidores).A struct is not permitted to declare a destructor (Destructors).

Semântica de valorValue semantics

Structs são tipos de valor (tipos de valor) e são considerados como semântica de valor.Structs are value types (Value types) and are said to have value semantics. As classes, por outro lado, são tipos de referência (tipos de referência) e são consideradas semânticas de referência.Classes, on the other hand, are reference types (Reference types) and are said to have reference semantics.

Uma variável de um tipo struct contém diretamente os dados da estrutura, enquanto uma variável de um tipo de classe contém uma referência aos dados, o último conhecido como um 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. Quando uma struct B contém um campo de instância do tipo A e A é um tipo struct, é um erro de tempo de compilação para A depender B ou um tipo construído 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. Uma struct X * depende diretamente de _ struct Y se X contiver um campo de instância do tipo Y .A struct X *directly depends on _ a struct Y if X contains an instance field of type Y. Dada essa definição, o conjunto completo de structs sobre o qual uma estrutura depende é o fechamento transitivo da relação _ depende diretamente de *.Given this definition, the complete set of structs upon which a struct depends is the transitive closure of the _ directly depends on* relationship. Por exemplo,For example

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

é um erro porque Node contém um campo de instância de seu próprio tipo.is an error because Node contains an instance field of its own type. Outro exemploAnother example

struct A { B b; }

struct B { C c; }

struct C { A a; }

é um erro porque cada um dos tipos A , B e C depende uns dos outros.is an error because each of the types A, B, and C depend on each other.

Com classes, é possível que duas variáveis referenciem o mesmo objeto e, assim, possíveis para operações em uma variável afetem o objeto referenciado pela outra variável.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. Com structs, as variáveis têm sua própria cópia dos dados (exceto no caso de ref variáveis de parâmetro e out ), e não é possível que as operações em um afetem a outra.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. Além disso, como structs não são tipos de referência, não é possível que os valores de um tipo de struct sejam null .Furthermore, because structs are not reference types, it is not possible for values of a struct type to be null.

Dada a declaraçãoGiven the declaration

struct Point
{
    public int x, y;

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

o fragmento de códigothe code fragment

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

gera o valor 10 .outputs the value 10. A atribuição de a para b cria uma cópia do valor e, b portanto, não é afetada pela atribuição para 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. PointEm vez disso, tinha sido declarado como uma classe, a saída seria 100 porque a e b referenciaria o mesmo objeto.Had Point instead been declared as a class, the output would be 100 because a and b would reference the same object.

HerançaInheritance

Todos os tipos de struct herdam implicitamente da classe System.ValueType , que, por sua vez, herda da classe object .All struct types implicitly inherit from the class System.ValueType, which, in turn, inherits from class object. Uma declaração struct pode especificar uma lista de interfaces implementadas, mas não é possível que uma declaração struct especifique uma classe 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.

Os tipos de struct nunca são abstratos e sempre são lacrados implicitamente.Struct types are never abstract and are always implicitly sealed. Os abstract sealed modificadores e, portanto, não são permitidos em uma declaração struct.The abstract and sealed modifiers are therefore not permitted in a struct declaration.

Como a herança não tem suporte para structs, a acessibilidade declarada de um Membro struct não pode ser protected ou protected internal .Since inheritance isn't supported for structs, the declared accessibility of a struct member cannot be protected or protected internal.

Membros de função em um struct não podem ser abstract ou virtual , e o override modificador é permitido apenas para substituir métodos herdados 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.

AtribuiçãoAssignment

A atribuição a uma variável de um tipo struct cria uma cópia do valor que está sendo atribuído.Assignment to a variable of a struct type creates a copy of the value being assigned. Isso difere da atribuição a uma variável de um tipo de classe, que copia a referência, mas não o objeto identificado pela referência.This differs from assignment to a variable of a class type, which copies the reference but not the object identified by the reference.

Semelhante a uma atribuição, quando uma struct é passada como um parâmetro de valor ou retornado como resultado de um membro de função, uma cópia da estrutura é criada.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. Uma struct pode ser passada por referência a um membro de função usando ref um out parâmetro ou.A struct may be passed by reference to a function member using a ref or out parameter.

Quando uma propriedade ou um indexador de uma struct é o destino de uma atribuição, a expressão de instância associada ao acesso de propriedade ou indexador deve ser classificada como uma variável.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. Se a expressão de instância for classificada como um valor, ocorrerá um erro em tempo de compilação.If the instance expression is classified as a value, a compile-time error occurs. Isso é descrito em mais detalhes em atribuição simples.This is described in further detail in Simple assignment.

Valores padrãoDefault values

Conforme descrito em valores padrão, vários tipos de variáveis são inicializados automaticamente para seu valor padrão quando eles são criados.As described in Default values, several kinds of variables are automatically initialized to their default value when they are created. Para variáveis de tipos de classe e outros tipos de referência, esse valor padrão é null .For variables of class types and other reference types, this default value is null. No entanto, como structs são tipos de valor que não podem ser null , o valor padrão de uma struct é o valor produzido pela configuração de todos os campos de tipo de valor para seu valor padrão e todos os campos de tipo de referência como 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.

Referindo-se à Point estrutura declarada acima, o exemploReferring to the Point struct declared above, the example

Point[] a = new Point[100];

Inicializa cada Point uma na matriz para o valor produzido Configurando x os y campos e como zero.initializes each Point in the array to the value produced by setting the x and y fields to zero.

O valor padrão de uma struct corresponde ao valor retornado pelo construtor padrão da struct (construtores padrão).The default value of a struct corresponds to the value returned by the default constructor of the struct (Default constructors). Ao contrário de uma classe, uma struct não tem permissão para declarar um construtor de instância sem parâmetros.Unlike a class, a struct is not permitted to declare a parameterless instance constructor. Em vez disso, cada struct implicitamente tem um construtor de instância sem parâmetros que sempre retorna o valor resultante da definição de todos os campos de tipo de valor para seu valor padrão e todos os campos de tipo de referência como 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.

As estruturas devem ser projetadas para considerar o estado de inicialização padrão um estado válido.Structs should be designed to consider the default initialization state a valid state. No exemploIn 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;
    }
}

o construtor de instância definido pelo usuário protege contra valores nulos somente quando ele é chamado explicitamente.the user-defined instance constructor protects against null values only where it is explicitly called. Nos casos em que uma KeyValuePair variável está sujeita à inicialização de valor padrão, os key value campos e serão nulos e o struct deverá estar preparado para lidar com esse 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.

Conversão boxing e unboxingBoxing and unboxing

Um valor de um tipo de classe pode ser convertido em tipo object ou em um tipo de interface que é implementado pela classe simplesmente tratando a referência como outro tipo em tempo de compilação.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. Da mesma forma, um valor do tipo object ou um valor de um tipo de interface pode ser convertido de volta para um tipo de classe sem alterar a referência (mas é claro que uma verificação de tipo em tempo de execução é necessária nesse 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).

Como structs não são tipos de referência, essas operações são implementadas de forma diferente para tipos struct.Since structs are not reference types, these operations are implemented differently for struct types. Quando um valor de um tipo struct é convertido em tipo object ou em um tipo de interface que é implementado pela estrutura, ocorre uma operação 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. Da mesma forma, quando um valor do tipo object ou um valor de um tipo de interface é convertido de volta em um tipo struct, ocorre uma operação de não-boxing.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. Uma diferença importante das mesmas operações em tipos de classe é que a boxing e a unboxing copiam o valor de struct para dentro ou para fora da instância em caixa.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. Portanto, após uma operação Boxing ou unboxing, as alterações feitas no struct não-Boxed não são refletidas no struct boxed.Thus, following a boxing or unboxing operation, changes made to the unboxed struct are not reflected in the boxed struct.

Quando um tipo de struct substitui um método virtual herdado de System.Object (como Equals , GetHashCode ou ToString ), a invocação do método virtual por meio de uma instância do tipo struct não faz com que a Boxing ocorra.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. Isso é verdadeiro mesmo quando a struct é usada como um parâmetro de tipo e a invocação ocorre por meio de uma instância do 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 exemplo: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>();
    }
}

A saída do programa é:The output of the program is:

1
2
3

Embora seja um estilo inadequado para ToString ter efeitos colaterais, o exemplo demonstra que nenhuma Boxing ocorreu para as três invocações 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().

Da mesma forma, a Boxing nunca ocorre implicitamente ao acessar um membro em um parâmetro de tipo restrito.Similarly, boxing never implicitly occurs when accessing a member on a constrained type parameter. Por exemplo, suponha que uma interface ICounter contenha um método Increment que possa ser usado para modificar um valor.For example, suppose an interface ICounter contains a method Increment which can be used to modify a value. Se ICounter é usado como uma restrição, a implementação do Increment método é chamada com uma referência à variável que Increment foi chamada on, nunca uma cópia em caixa.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>();
    }
}

A primeira chamada para Increment modifica o valor na variável x .The first call to Increment modifies the value in the variable x. Isso não é equivalente à segunda chamada para Increment , que modifica o valor em uma cópia em caixa de x .This is not equivalent to the second call to Increment, which modifies the value in a boxed copy of x. Assim, a saída do programa é:Thus, the output of the program is:

0
1
1

Para obter mais detalhes sobre boxing e unboxing, consulte boxing e unboxing.For further details on boxing and unboxing, see Boxing and unboxing.

Significado dissoMeaning of this

Dentro de um construtor de instância ou membro de função de instância de uma classe, this é classificado como um valor.Within an instance constructor or instance function member of a class, this is classified as a value. Portanto, embora this possa ser usado para fazer referência à instância para a qual o membro de função foi invocado, não é possível atribuir a this em um membro de função de uma classe.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 um construtor de instância de uma struct, this corresponde a um out parâmetro do tipo struct e, dentro de um membro da função de instância de uma struct, this corresponde a um ref parâmetro do 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. Em ambos os casos, this é classificado como uma variável, e é possível modificar toda a estrutura para a qual o membro da função foi invocado, atribuindo a this ou passando isso como um ref out parâmetro ou.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

Conforme descrito em valores padrão, o valor padrão de uma struct consiste no valor que resulta da definição de todos os campos de tipo de valor com o valor padrão e a todos os campos de tipo de referência como 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 esse motivo, uma struct não permite que declarações de campo de instância incluam inicializadores de variável.For this reason, a struct does not permit instance field declarations to include variable initializers. Essa restrição se aplica somente a campos de instância.This restriction applies only to instance fields. Os campos estáticos de uma estrutura têm permissão para incluir inicializadores de variável.Static fields of a struct are permitted to include variable initializers.

O exemploThe example

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

está em erro porque as declarações de campo de instância incluem inicializadores de variável.is in error because the instance field declarations include variable initializers.

ConstrutoresConstructors

Ao contrário de uma classe, uma struct não tem permissão para declarar um construtor de instância sem parâmetros.Unlike a class, a struct is not permitted to declare a parameterless instance constructor. Em vez disso, cada struct implicitamente tem um construtor de instância sem parâmetros que sempre retorna o valor resultante da definição de todos os campos de tipo de valor para seu valor padrão e todos os campos de tipo de referência como NULL (construtores padrão).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). Uma struct pode declarar construtores de instância com parâmetros.A struct can declare instance constructors having parameters. Por exemplo,For example

struct Point
{
    int x, y;

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

Dada a declaração acima, as instruçõesGiven the above declaration, the statements

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

Crie um Point com x e y inicializado como zero.both create a Point with x and y initialized to zero.

Um construtor de instância de struct não tem permissão para incluir um inicializador de construtor do formulário base(...) .A struct instance constructor is not permitted to include a constructor initializer of the form base(...).

Se o construtor da instância de struct não especificar um inicializador de construtor, a this variável corresponderá a um out parâmetro do tipo struct e semelhante a um out parâmetro, this deverá ser definitivamente atribuída (atribuiçãodefinida) em cada local em que o Construtor retornar.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. Se o construtor da instância de struct especificar um inicializador de construtor, a this variável corresponderá a um ref parâmetro do tipo struct e, semelhante a um ref parâmetro, this será considerada definitivamente atribuída na entrada ao corpo do construtor.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. Considere a implementação do construtor de instância abaixo: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
    }
}

Nenhuma função de membro de instância (incluindo os acessadores set para as propriedades X e Y ) pode ser chamada até que todos os campos da estrutura que está sendo construída tenham sido definitivamente atribuídos.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. A única exceção envolve Propriedades implementadas automaticamente (Propriedades implementadas automaticamente).The only exception involves automatically implemented properties (Automatically implemented properties). As regras de atribuição definidas (expressões de atribuição simples) especificamente isentam a atribuição a uma propriedade automática de um tipo struct dentro de um construtor de instância desse tipo struct: tal atribuição é considerada uma atribuição definitiva do campo de apoio oculto da propriedade 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. Assim, é permitido o seguinte: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
    }

DestruidoresDestructors

Um struct não tem permissão para declarar um destruidor.A struct is not permitted to declare a destructor.

Construtores estáticosStatic constructors

Construtores estáticos para structs seguem a maioria das mesmas regras que para classes.Static constructors for structs follow most of the same rules as for classes. A execução de um construtor estático para um tipo de struct é disparada pelo primeiro dos seguintes eventos para ocorrer dentro de um domínio de aplicativo: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:

  • Um membro estático do tipo struct é referenciado.A static member of the struct type is referenced.
  • Um construtor declarado explicitamente do tipo struct é chamado.An explicitly declared constructor of the struct type is called.

A criação de valores padrão (valores padrão) de tipos de struct não dispara o construtor estático.The creation of default values (Default values) of struct types does not trigger the static constructor. (Um exemplo disso é o valor inicial dos elementos em uma matriz.)(An example of this is the initial value of elements in an array.)

Exemplos de structStruct examples

O exemplo a seguir mostra dois exemplos significativos de struct como usar tipos para criar tipos que podem ser usados de forma semelhante aos tipos predefinidos da linguagem, mas com semânticas modificadas.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 inteiro do banco de dadosDatabase integer type

A DBInt struct abaixo implementa um tipo inteiro que pode representar o conjunto completo de valores do int tipo, além de um estado adicional que indica um valor desconhecido.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. Um tipo com essas características é comumente usado em bancos de dados.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 booliano do banco de dadosDatabase boolean type

A DBBool estrutura abaixo implementa um tipo lógico de três valores.The DBBool struct below implements a three-valued logical type. Os valores possíveis desse tipo são DBBool.True , DBBool.False e DBBool.Null , em que o Null membro indica um valor desconhecido.The possible values of this type are DBBool.True, DBBool.False, and DBBool.Null, where the Null member indicates an unknown value. Esses tipos lógicos de três valores são comumente usados em bancos de dados.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";
    }
}