StructStructs

Gli struct sono simili alle classi in quanto rappresentano strutture dei dati che possono contenere membri dati e membri di funzione.Structs are similar to classes in that they represent data structures that can contain data members and function members. Tuttavia, a differenza delle classi, gli struct sono tipi valore e non richiedono l'allocazione dell'heap.However, unlike classes, structs are value types and do not require heap allocation. Una variabile di un tipo struct contiene direttamente i dati dello struct, mentre una variabile di un tipo di classe contiene un riferimento ai dati, il secondo noto come oggetto.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.

I tipi struct sono particolarmente utili per strutture dati di piccole dimensioni che hanno una semantica di valori.Structs are particularly useful for small data structures that have value semantics. I numeri complessi, i punti di un sistema di coordinate o le coppie chiave-valore di un dizionario sono buoni esempi di struct.Complex numbers, points in a coordinate system, or key-value pairs in a dictionary are all good examples of structs. La chiave di queste strutture di dati è che hanno pochi membri dati, che non richiedono l'uso dell'ereditarietà o dell'identità referenziale e che possono essere implementati facilmente usando la semantica del valore in cui l'assegnazione copia il valore anziché il riferimento.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.

Come descritto in tipi semplici, i tipi semplici forniti da C#, ad esempio int , double e bool , sono in realtà tutti i tipi struct.As described in Simple types, the simple types provided by C#, such as int, double, and bool, are in fact all struct types. Proprio come questi tipi predefiniti sono struct, è anche possibile usare gli struct e l'overload degli operatori per implementare nuovi tipi "primitivi" nel linguaggio 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. Alla fine di questo capitolo sono riportati due esempi di tali tipi (esempi di struct).Two examples of such types are given at the end of this chapter (Struct examples).

Dichiarazioni structStruct declarations

Un struct_declaration è un type_declaration (dichiarazioni di tipo) che dichiara un nuovo 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 ';'?
    ;

Un struct_declaration è costituito da un set facoltativo di attributi (attributi), seguito da un set facoltativo di struct_modifier s (modificatori struct), seguito da un partial modificatore facoltativo, seguito dalla parola chiave struct e da un identificatore che denomina lo struct, seguito da una specifica di type_parameter_list facoltativa (parametri di tipo), seguiti da una specifica di struct_interfaces facoltativa (modificatore parziale), seguiti da una specifica type_parameter_constraints_clause s facoltativa (vincoli di parametro di tipo), seguiti da un struct_body (corpo della struct), seguiti facoltativA 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.

Modificatori structStruct modifiers

Un struct_declaration può includere facoltativamente una sequenza di modificatori struct:A struct_declaration may optionally include a sequence of struct modifiers:

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

Si tratta di un errore in fase di compilazione perché lo stesso modificatore venga visualizzato più volte in una dichiarazione struct.It is a compile-time error for the same modifier to appear multiple times in a struct declaration.

I modificatori di una dichiarazione di struct hanno lo stesso significato di quelli di una dichiarazione di classe (dichiarazioni di classe).The modifiers of a struct declaration have the same meaning as those of a class declaration (Class declarations).

Modificatore parzialePartial modifier

Il partial modificatore indica che questo struct_declaration è una dichiarazione di tipo parziale.The partial modifier indicates that this struct_declaration is a partial type declaration. Più dichiarazioni di struct parziali con lo stesso nome in uno spazio dei nomi di inclusione o in una dichiarazione di tipo combinano per formare una dichiarazione struct, seguendo le regole specificate in tipi parziali.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.

Interfacce structStruct interfaces

Una dichiarazione struct può includere una specifica struct_interfaces , nel qual caso lo struct viene definito per implementare direttamente i tipi di interfaccia specificati.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
    ;

Le implementazioni dell'interfaccia sono illustrate ulteriormente nelle implementazioni dell'interfaccia.Interface implementations are discussed further in Interface implementations.

Corpo dello structStruct body

Il struct_body di uno struct definisce i membri della struttura.The struct_body of a struct defines the members of the struct.

struct_body
    : '{' struct_member_declaration* '}'
    ;

Membri structStruct members

I membri di uno struct sono costituiti dai membri introdotti dal struct_member_declaration s e dai membri ereditati dal 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
    ;

Ad eccezione delle differenze indicate nelle differenze tra le classi e gli struct, le descrizioni dei membri della classe forniti nei membri della classe tramite funzioni asincrone si applicano anche ai membri 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.

Differenze di classi e structClass and struct differences

Gli struct differiscono dalle classi in diversi modi importanti:Structs differ from classes in several important ways:

  • Gli struct sono tipi di valore (semantica del valore).Structs are value types (Value semantics).
  • Tutti i tipi struct ereditano in modo implicito dalla classe System.ValueType (ereditarietà).All struct types implicitly inherit from the class System.ValueType (Inheritance).
  • L'assegnazione a una variabile di un tipo struct crea una copia del valore assegnato (assegnazione).Assignment to a variable of a struct type creates a copy of the value being assigned (Assignment).
  • Il valore predefinito di uno struct è il valore prodotto impostando tutti i campi di tipo valore sul valore predefinito e tutti i campi di tipo riferimento su null (valori predefiniti).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).
  • Le operazioni di conversione boxing e unboxing vengono usate per eseguire la conversione tra un tipo di struct e object (conversione boxing eunboxing).Boxing and unboxing operations are used to convert between a struct type and object (Boxing and unboxing).
  • Il significato di this è diverso per gli struct (questo accesso).The meaning of this is different for structs (This access).
  • Le dichiarazioni dei campi di istanza per uno struct non possono includere inizializzatori di variabile (inizializzatori di campo).Instance field declarations for a struct are not permitted to include variable initializers (Field initializers).
  • Uno struct non è autorizzato a dichiarare un costruttore di istanza senza parametri (costruttori).A struct is not permitted to declare a parameterless instance constructor (Constructors).
  • Uno struct non è autorizzato a dichiarareun distruttore (distruttori).A struct is not permitted to declare a destructor (Destructors).

Semantica del valoreValue semantics

Gli struct sono tipi di valore (tipi di valore) e hanno una semantica del valore.Structs are value types (Value types) and are said to have value semantics. Le classi, d'altra parte, sono tipi di riferimento (tipi di riferimento) e hanno una semantica di riferimento.Classes, on the other hand, are reference types (Reference types) and are said to have reference semantics.

Una variabile di un tipo struct contiene direttamente i dati dello struct, mentre una variabile di un tipo di classe contiene un riferimento ai dati, il secondo noto come oggetto.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 uno struct B contiene un campo di istanza di tipo A e A è un tipo struct, si tratta di un errore in fase di compilazione per A da dipendere da B o da un tipo costruito da 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. Uno struct X * dipende direttamente da _ uno struct Y se X contiene un campo di istanza di tipo Y .A struct X *directly depends on _ a struct Y if X contains an instance field of type Y. Data questa definizione, il set completo di struct su cui dipende uno struct è la chiusura transitiva di _ direttamente dipende da * Relationship.Given this definition, the complete set of structs upon which a struct depends is the transitive closure of the _ directly depends on* relationship. Ad esempio:For example

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

è un errore perché Node contiene un campo di istanza di un proprio tipo.is an error because Node contains an instance field of its own type. Un altro esempioAnother example

struct A { B b; }

struct B { C c; }

struct C { A a; }

è un errore perché ognuno dei tipi A , B e dipende l' C uno dall'altro.is an error because each of the types A, B, and C depend on each other.

Con le classi, è possibile che due variabili facciano riferimento allo stesso oggetto ed è quindi possibile che le operazioni su una variabile influiscano sull'oggetto a cui fa riferimento l'altra variabile.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. Con gli struct, le variabili hanno ciascuna una propria copia dei dati (tranne nel caso delle variabili di ref out parametro e) e non è possibile che le operazioni su uno influiscano sull'altro.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. Inoltre, poiché gli struct non sono tipi di riferimento, non è possibile che i valori di un tipo struct siano null .Furthermore, because structs are not reference types, it is not possible for values of a struct type to be null.

Data la dichiarazioneGiven the declaration

struct Point
{
    public int x, y;

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

frammento di codicethe code fragment

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

Restituisce il valore 10 .outputs the value 10. L'assegnazione di a per b Crea una copia del valore e pertanto non b è interessata dall'assegnazione 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. Era Point stato invece dichiarato come una classe, l'output è dovuto al fatto 100 a che e b fanno riferimento allo stesso oggetto.Had Point instead been declared as a class, the output would be 100 because a and b would reference the same object.

EreditarietàInheritance

Tutti i tipi struct ereditano in modo implicito dalla classe System.ValueType , che a sua volta eredita dalla classe object .All struct types implicitly inherit from the class System.ValueType, which, in turn, inherits from class object. Una dichiarazione struct può specificare un elenco di interfacce implementate, ma non è possibile che una dichiarazione struct specifichi una 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.

I tipi struct non sono mai astratti e sono sempre implicitamente sealed.Struct types are never abstract and are always implicitly sealed. I abstract sealed modificatori e non sono pertanto consentiti in una dichiarazione struct.The abstract and sealed modifiers are therefore not permitted in a struct declaration.

Poiché l'ereditarietà non è supportata per gli struct, l'accessibilità dichiarata di un membro struct non può essere protected o protected internal .Since inheritance isn't supported for structs, the declared accessibility of a struct member cannot be protected or protected internal.

I membri di funzione in uno struct non possono essere abstract o virtual e il override modificatore è consentito solo per eseguire l'override dei metodi ereditati da 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.

AssegnazioneAssignment

L'assegnazione a una variabile di un tipo struct crea una copia del valore da assegnare.Assignment to a variable of a struct type creates a copy of the value being assigned. Questo comportamento è diverso dall'assegnazione a una variabile di un tipo di classe, che copia il riferimento ma non l'oggetto identificato dal riferimento.This differs from assignment to a variable of a class type, which copies the reference but not the object identified by the reference.

Analogamente a un'assegnazione, quando una struttura viene passata come parametro di valore o restituita come risultato di un membro di funzione, viene creata una copia dello struct.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. Uno struct può essere passato per riferimento a un membro di funzione usando ref un out parametro o.A struct may be passed by reference to a function member using a ref or out parameter.

Quando una proprietà o un indicizzatore di uno struct è la destinazione di un'assegnazione, l'espressione dell'istanza associata alla proprietà o all'indicizzatore deve essere classificata come variabile.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 l'espressione dell'istanza è classificata come valore, si verifica un errore in fase di compilazione.If the instance expression is classified as a value, a compile-time error occurs. Questa operazione viene descritta più dettagliatamente nell' assegnazione semplice.This is described in further detail in Simple assignment.

Valori predefinitiDefault values

Come descritto in valori predefiniti, i diversi tipi di variabili vengono inizializzati automaticamente sul valore predefinito quando vengono creati.As described in Default values, several kinds of variables are automatically initialized to their default value when they are created. Per le variabili dei tipi di classe e altri tipi di riferimento, questo valore predefinito è null .For variables of class types and other reference types, this default value is null. Tuttavia, poiché gli struct sono tipi di valore che non possono essere null , il valore predefinito di uno struct è il valore prodotto impostando tutti i campi di tipo valore sul valore predefinito e tutti i campi di tipo riferimento su 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.

Facendo riferimento allo Point struct dichiarato in precedenza, l'esempioReferring to the Point struct declared above, the example

Point[] a = new Point[100];

Inizializza ogni oggetto Point nella matrice sul valore prodotto impostando i x campi e y su zero.initializes each Point in the array to the value produced by setting the x and y fields to zero.

Il valore predefinito di uno struct corrisponde al valore restituito dal costruttore predefinito dello struct (costruttori predefiniti).The default value of a struct corresponds to the value returned by the default constructor of the struct (Default constructors). A differenza di una classe, uno struct non è autorizzato a dichiarare un costruttore di istanza senza parametri.Unlike a class, a struct is not permitted to declare a parameterless instance constructor. Al contrario, ogni struct dispone implicitamente di un costruttore di istanza senza parametri che restituisce sempre il valore risultante dall'impostazione di tutti i campi di tipo valore sul valore predefinito e di tutti i campi di tipo riferimento su 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.

Gli struct devono essere progettati per considerare lo stato di inizializzazione predefinito uno stato valido.Structs should be designed to consider the default initialization state a valid state. Nell'esempioIn 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;
    }
}

il costruttore di istanze definito dall'utente protegge da valori null solo se viene chiamato in modo esplicito.the user-defined instance constructor protects against null values only where it is explicitly called. Nei casi in cui una KeyValuePair variabile è soggetta all'inizializzazione predefinita dei valori, i key value campi e saranno null e la struttura deve essere preparata per la gestione di questo stato.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.

Boxing e unboxingBoxing and unboxing

Un valore di un tipo di classe può essere convertito nel tipo object o in un tipo di interfaccia implementato dalla classe semplicemente trattando il riferimento come un altro tipo in fase di compilazione.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. Analogamente, un valore di tipo object o un valore di un tipo di interfaccia può essere convertito di nuovo in un tipo di classe senza modificare il riferimento (ma, in questo caso, è necessario un controllo del tipo in fase di esecuzione).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).

Poiché gli struct non sono tipi di riferimento, queste operazioni vengono implementate in modo diverso per i tipi struct.Since structs are not reference types, these operations are implemented differently for struct types. Quando un valore di un tipo struct viene convertito nel tipo object o in un tipo di interfaccia implementato dallo struct, viene eseguita un'operazione di conversione 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. Analogamente, quando un valore di tipo object o un valore di un tipo di interfaccia viene riconvertito in un tipo struct, viene eseguita un'operazione di conversione 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 differenza fondamentale tra le stesse operazioni sui tipi di classe è che la conversione boxing e unboxing copia il valore dello struct all'interno o all'esterno dell'istanza boxed.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. Quindi, dopo un'operazione di conversione boxing o unboxing, le modifiche apportate allo struct unboxed non vengono riflesse nello struct boxed.Thus, following a boxing or unboxing operation, changes made to the unboxed struct are not reflected in the boxed struct.

Quando un tipo struct esegue l'override di un metodo virtuale ereditato da System.Object (ad esempio Equals , GetHashCode o ToString ), la chiamata del metodo virtuale tramite un'istanza del tipo struct non provoca la conversione boxing.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. Questo vale anche quando lo struct viene usato come parametro di tipo e la chiamata viene eseguita tramite un'istanza del tipo di parametro di 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. Ad esempio: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>();
    }
}

L'output del programma è:The output of the program is:

1
2
3

Sebbene non sia uno stile valido per ToString avere effetti collaterali, nell'esempio viene dimostrato che non si è verificata alcuna conversione boxing per le tre chiamate di 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().

Analogamente, la conversione boxing non viene mai eseguita in modo implicito quando si accede a un membro in un parametro di tipo vincolato.Similarly, boxing never implicitly occurs when accessing a member on a constrained type parameter. Si supponga, ad esempio, ICounter che un'interfaccia contenga un metodo Increment che può essere utilizzato per modificare un valore.For example, suppose an interface ICounter contains a method Increment which can be used to modify a value. Se ICounter viene usato come vincolo, l'implementazione del Increment metodo viene chiamata con un riferimento alla variabile che Increment è stata chiamata su, mai una copia boxed.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 prima chiamata a Increment modifica il valore nella variabile x .The first call to Increment modifies the value in the variable x. Questa operazione non equivale alla seconda chiamata a Increment , che modifica il valore in una copia boxed di x .This is not equivalent to the second call to Increment, which modifies the value in a boxed copy of x. Quindi, l'output del programma è:Thus, the output of the program is:

0
1
1

Per ulteriori informazioni su conversione boxing e unboxing, vedere conversione boxing eunboxing.For further details on boxing and unboxing, see Boxing and unboxing.

Significato di questoMeaning of this

All'interno di un costruttore di istanza o di un membro della funzione di istanza di una classe, this è classificato come valore.Within an instance constructor or instance function member of a class, this is classified as a value. Pertanto, while this può essere utilizzato per fare riferimento all'istanza per la quale è stato richiamato il membro della funzione, non è possibile assegnare a this in un membro di funzione di una 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.

All'interno di un costruttore di istanza di uno struct, this corrisponde a un out parametro del tipo struct e all'interno di un membro della funzione di istanza di uno struct this corrisponde a un ref parametro 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. In entrambi i casi, this è classificato come una variabile ed è possibile modificare l'intero struct per cui il membro della funzione è stato richiamato assegnando a this o passando come ref out parametro o.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.

Inizializzatori di campoField initializers

Come descritto in valori predefiniti, il valore predefinito di uno struct è costituito dal valore risultante dall'impostazione di tutti i campi di tipo valore sul valore predefinito e di tutti i campi di tipo riferimento su 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. Per questo motivo, uno struct non consente alle dichiarazioni dei campi di istanza di includere inizializzatori di variabili.For this reason, a struct does not permit instance field declarations to include variable initializers. Questa restrizione si applica solo ai campi di istanza.This restriction applies only to instance fields. I campi statici di uno struct possono includere inizializzatori di variabile.Static fields of a struct are permitted to include variable initializers.

L'esempio:The example

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

è in errore perché le dichiarazioni dei campi di istanza includono inizializzatori di variabile.is in error because the instance field declarations include variable initializers.

CostruttoriConstructors

A differenza di una classe, uno struct non è autorizzato a dichiarare un costruttore di istanza senza parametri.Unlike a class, a struct is not permitted to declare a parameterless instance constructor. Al contrario, ogni struct dispone implicitamente di un costruttore di istanza senza parametri che restituisce sempre il valore risultante dall'impostazione di tutti i campi di tipo valore sul valore predefinito e di tutti i campi di tipo riferimento su null (costruttori predefiniti).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). Uno struct può dichiarare i costruttori di istanza con parametri.A struct can declare instance constructors having parameters. Ad esempio:For example

struct Point
{
    int x, y;

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

Data la dichiarazione precedente, le istruzioniGiven the above declaration, the statements

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

entrambi creano un oggetto Point con x e y inizializzato su zero.both create a Point with x and y initialized to zero.

Un costruttore di istanze struct non è autorizzato a includere un inizializzatore del costruttore del modulo base(...) .A struct instance constructor is not permitted to include a constructor initializer of the form base(...).

Se il costruttore di istanze struct non specifica un inizializzatore di costruttore, la this variabile corrispondente a un out parametro del tipo struct e simile a un out parametro this deve essere assegnata definitivamente (assegnazione definita) in ogni posizione in cui viene restituito il costruttore.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 il costruttore di istanze struct specifica un inizializzatore di costruttore, la this variabile corrisponde a un ref parametro del tipo struct e analogamente a un ref parametro this viene considerato definitivamente assegnato alla voce al corpo del costruttore.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. Si consideri l'implementazione del costruttore di istanze seguente: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
    }
}

Non è possibile chiamare alcuna funzione membro di istanza (incluse le funzioni di accesso set per le proprietà X e Y ) finché tutti i campi dello struct costruito non sono stati assegnati definitivamente.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. L'unica eccezione riguarda le proprietà implementate automaticamente (proprietà implementate automaticamente).The only exception involves automatically implemented properties (Automatically implemented properties). Le regole di assegnazione definite (espressioni di assegnazione semplice) estendono in modo specifico l'assegnazione a una proprietà automatica di un tipo struct all'interno di un costruttore di istanza del tipo struct. tale assegnazione viene considerata un'assegnazione definita del campo sottostante nascosto della proprietà automatica.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. Di conseguenza, sono consentiti gli elementi seguenti: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
    }

DistruttoriDestructors

Uno struct non è autorizzato a dichiarare un distruttore.A struct is not permitted to declare a destructor.

Costruttori staticiStatic constructors

I costruttori statici per gli struct seguono la maggior parte delle stesse regole delle classi.Static constructors for structs follow most of the same rules as for classes. L'esecuzione di un costruttore statico per un tipo struct viene attivata dal primo degli eventi seguenti che si verificano all'interno di un dominio dell'applicazione: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:

  • Viene fatto riferimento A un membro statico del tipo struct.A static member of the struct type is referenced.
  • Viene chiamato un costruttore dichiarato in modo esplicito del tipo struct.An explicitly declared constructor of the struct type is called.

La creazione di valori predefiniti (valori predefiniti) di tipi struct non attiva il costruttore statico.The creation of default values (Default values) of struct types does not trigger the static constructor. Un esempio è il valore iniziale degli elementi in una matrice.(An example of this is the initial value of elements in an array.)

Esempi di structStruct examples

Di seguito vengono illustrati due esempi significativi di utilizzo dei struct tipi per creare tipi che possono essere utilizzati in modo analogo ai tipi predefiniti del linguaggio, ma con la semantica modificata.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 Integer databaseDatabase integer type

Lo DBInt struct seguente implementa un tipo integer che può rappresentare il set completo di valori del int tipo, più uno stato aggiuntivo che indica un valore sconosciuto.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 queste caratteristiche viene comunemente usato nei database.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 di database booleanoDatabase boolean type

Lo DBBool struct seguente implementa un tipo logico a tre valori.The DBBool struct below implements a three-valued logical type. I valori possibili di questo tipo sono DBBool.True , DBBool.False e DBBool.Null , dove il Null membro indica un valore sconosciuto.The possible values of this type are DBBool.True, DBBool.False, and DBBool.Null, where the Null member indicates an unknown value. Tali tipi logici a tre valori sono comunemente utilizzati nei database di.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";
    }
}