StructsStructs

Les structs sont similaires aux classes en ce qu’ils représentent des structures de données qui peuvent contenir des membres de données et des fonctions membres.Structs are similar to classes in that they represent data structures that can contain data members and function members. Toutefois, contrairement aux classes, les structs sont des types valeur et ne nécessitent pas d’allocation de tas.However, unlike classes, structs are value types and do not require heap allocation. Une variable d’un type struct contient directement les données de la structure, alors qu’une variable d’un type de classe contient une référence aux données, la dernière appelée objet.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.

Les structures sont particulièrement utiles pour les petites structures de données qui ont une sémantique par rapport à leurs valeurs.Structs are particularly useful for small data structures that have value semantics. Les nombres complexes, les points dans un système de coordonnées ou les paires clé-valeur dans un dictionnaire sont de bons exemples de structures.Complex numbers, points in a coordinate system, or key-value pairs in a dictionary are all good examples of structs. La clé de ces structures de données est qu’elles ont peu de membres de données, qu’elles ne nécessitent pas l’utilisation de l’héritage ou de l’identité référentielle, et qu’elles peuvent être implémentées facilement à l’aide de la sémantique de valeur où l’assignation copie la valeur au lieu de la référence.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.

Comme décrit dans types simples, les types simples fournis par C#, tels que int, double et bool, sont en fait tous des types struct.As described in Simple types, the simple types provided by C#, such as int, double, and bool, are in fact all struct types. Tout comme ces types prédéfinis sont des structs, il est également possible d’utiliser des structs et la surcharge d’opérateur pour implémenter de nouveaux types « C# primitifs » dans le langage.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. Deux exemples de ces types sont fournis à la fin de ce chapitre (exemples de struct).Two examples of such types are given at the end of this chapter (Struct examples).

Déclarations de structStruct declarations

Un struct_declaration est un type_declaration (déclarations de type) qui déclare un nouveau 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 se compose d’un ensemble facultatif d' attributs (attributs), suivi d’un ensemble facultatif de struct_modifiers (modificateurs de struct), suivi d’un modificateur facultatif partial, suivi de l’option mot clé struct et identificateur qui nomme le struct, suivi d’une spécification type_parameter_list facultative (paramètres de type), suivie d’une spécification struct_interfaces facultative (partielle ),suivis d’une spécification type_parameter_constraints_clauses facultative (contraintes deparamètre de type), suivie d’un struct_body (corps de struct), éventuellement suivi d’un point-virgule.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.

Modificateurs de structStruct modifiers

Un struct_declaration peut éventuellement inclure une séquence de modificateurs de struct :A struct_declaration may optionally include a sequence of struct modifiers:

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

Il s’agit d’une erreur au moment de la compilation pour que le même modificateur apparaisse plusieurs fois dans une déclaration de struct.It is a compile-time error for the same modifier to appear multiple times in a struct declaration.

Les modificateurs d’une déclaration de struct ont la même signification que ceux d’une déclaration de classe (déclarations de classe).The modifiers of a struct declaration have the same meaning as those of a class declaration (Class declarations).

Modificateur partielPartial modifier

Le modificateur partial indique que ce struct_declaration est une déclaration de type partielle.The partial modifier indicates that this struct_declaration is a partial type declaration. Plusieurs déclarations de struct partielles portant le même nom dans un espace de noms englobant ou une déclaration de type sont combinées pour former une déclaration de struct, suivant les règles spécifiées dans les types partiels.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

Une déclaration de struct peut inclure une spécification struct_interfaces , auquel cas le struct est dit d’implémenter directement les types d’interfaces donnés.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
    ;

Les implémentations d’interface sont abordées plus en détail dans implémentations d’interface.Interface implementations are discussed further in Interface implementations.

Corps du structStruct body

Le struct_body d’un struct définit les membres du struct.The struct_body of a struct defines the members of the struct.

struct_body
    : '{' struct_member_declaration* '}'
    ;

Membres de structStruct members

Les membres d’un struct se composent des membres introduits par ses struct_member_declarationet des membres hérités du type 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
    ;

À l’exception des différences constatées dans les différences entre les classes et les structs, les descriptions des membres de classe fournis dans les membres de classe par le biais d' itérateurs s’appliquent également aux membres de la structure.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.

Différences entre les classes et les structsClass and struct differences

Les structs diffèrent des classes de plusieurs manières importantes :Structs differ from classes in several important ways:

  • Les structs sont des types valeur (sémantique de valeur).Structs are value types (Value semantics).
  • Tous les types struct héritent implicitement de la classe System.ValueType (héritage).All struct types implicitly inherit from the class System.ValueType (Inheritance).
  • L’assignation à une variable d’un type struct crée une copie de la valeur assignée (affectation).Assignment to a variable of a struct type creates a copy of the value being assigned (Assignment).
  • La valeur par défaut d’un struct correspond à la valeur produite en affectant à tous les champs de type valeur leur valeur par défaut et à tous les champs de type référence la valeur null (valeurs par défaut).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).
  • Les opérations de boxing et d’unboxing sont utilisées pour effectuer une conversion entre un type struct et object (boxing et unboxing).Boxing and unboxing operations are used to convert between a struct type and object (Boxing and unboxing).
  • La signification de this est différente pour les structs (cet accès).The meaning of this is different for structs (This access).
  • Les déclarations de champ d’instance pour un struct ne sont pas autorisées à inclure des initialiseurs de variable (initialiseurs de champ).Instance field declarations for a struct are not permitted to include variable initializers (Field initializers).
  • Un struct n’est pas autorisé à déclarer un constructeur d’instance sans paramètre (constructeurs).A struct is not permitted to declare a parameterless instance constructor (Constructors).
  • Un struct n’est pas autorisé à déclarer un destructeur (destructeurs).A struct is not permitted to declare a destructor (Destructors).

Sémantique de valeurValue semantics

Les structs sont des types valeur (types valeur) et sont dits sémantiques de valeur.Structs are value types (Value types) and are said to have value semantics. En revanche, les classes sont des types référence (types référence) et sont dites avoir une sémantique de référence.Classes, on the other hand, are reference types (Reference types) and are said to have reference semantics.

Une variable d’un type struct contient directement les données de la structure, alors qu’une variable d’un type de classe contient une référence aux données, la dernière appelée objet.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. Lorsqu’un struct B contient un champ d’instance de type A et A est un type struct, il s’agit d’une erreur de compilation pour A qui dépend de B ou d’un type construit à 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 dépend directement d' un struct Y si X contient un champ d’instance de type Y.A struct X directly depends on a struct Y if X contains an instance field of type Y. Compte tenu de cette définition, l’ensemble complet des structs dont dépend un struct est la fermeture transitive de l' directement dépend de la relation.Given this definition, the complete set of structs upon which a struct depends is the transitive closure of the directly depends on relationship. Exemple :For example

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

est une erreur, car Node contient un champ d’instance de son propre type.is an error because Node contains an instance field of its own type. Autre exempleAnother example

struct A { B b; }

struct B { C c; }

struct C { A a; }

est une erreur, car chacun des types A, B et C dépend l’un de l’autre.is an error because each of the types A, B, and C depend on each other.

Avec les classes, deux variables peuvent faire référence au même objet et, par conséquent, les opérations sur une variable peuvent affecter l’objet référencé par l’autre 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. Avec les structs, les variables ont chacune leur propre copie des données (sauf dans le cas des variables de paramètre ref et out), et il n’est pas possible pour les opérations sur l’une d’affecter l’autre.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. En outre, étant donné que les structs ne sont pas des types référence, il n’est pas possible que les valeurs d’un type struct soient null.Furthermore, because structs are not reference types, it is not possible for values of a struct type to be null.

Compte tenu de la déclarationGiven the declaration

struct Point
{
    public int x, y;

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

fragment de codethe code fragment

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

génère la valeur 10.outputs the value 10. L’assignation de a à b crée une copie de la valeur et b n’est donc pas affectée par l’assignation à 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. Si Point a été déclarée en tant que classe, la sortie est 100, car a et b référencent le même objet.Had Point instead been declared as a class, the output would be 100 because a and b would reference the same object.

HéritageInheritance

Tous les types struct héritent implicitement de la classe System.ValueType, qui hérite à son tour de la classe object.All struct types implicitly inherit from the class System.ValueType, which, in turn, inherits from class object. Une déclaration de struct peut spécifier une liste d’interfaces implémentées, mais il n’est pas possible pour une déclaration de struct de spécifier une classe de 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.

Les types struct ne sont jamais abstraits et sont toujours implicitement sealed.Struct types are never abstract and are always implicitly sealed. Les modificateurs abstract et sealed ne sont donc pas autorisés dans une déclaration de struct.The abstract and sealed modifiers are therefore not permitted in a struct declaration.

Étant donné que l’héritage n’est pas pris en charge pour les structs, l’accessibilité déclarée d’un membre de struct ne peut pas être protected ou protected internal.Since inheritance isn't supported for structs, the declared accessibility of a struct member cannot be protected or protected internal.

Les fonctions membres d’un struct ne peuvent pas être abstract ou virtual, et le modificateur override est autorisé uniquement à substituer des méthodes héritées 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.

AttributionAssignment

L’assignation à une variable d’un type struct crée une copie de la valeur assignée.Assignment to a variable of a struct type creates a copy of the value being assigned. Cela diffère d’une assignation à une variable d’un type de classe, qui copie la référence, mais pas l’objet identifié par la référence.This differs from assignment to a variable of a class type, which copies the reference but not the object identified by the reference.

Semblable à une assignation, lorsqu’un struct est passé en tant que paramètre de valeur ou retourné comme résultat d’un membre de fonction, une copie de la structure est créée.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 peut être passé par référence à un membre de fonction à l’aide d’un paramètre ref ou out.A struct may be passed by reference to a function member using a ref or out parameter.

Quand une propriété ou un indexeur d’un struct est la cible d’une assignation, l’expression d’instance associée à l’accès à la propriété ou à l’indexeur doit être classée en tant que 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 l’expression d’instance est classée en tant que valeur, une erreur de compilation se produit.If the instance expression is classified as a value, a compile-time error occurs. Cela est décrit plus en détail dans la section affectation simple.This is described in further detail in Simple assignment.

Valeurs par défautDefault values

Comme décrit dans valeurs par défaut, plusieurs types de variables sont automatiquement initialisés à leur valeur par défaut lors de leur création.As described in Default values, several kinds of variables are automatically initialized to their default value when they are created. Pour les variables de types classe et autres types référence, cette valeur par défaut est null.For variables of class types and other reference types, this default value is null. Toutefois, étant donné que les structs sont des types valeur qui ne peuvent pas être null, la valeur par défaut d’un struct est la valeur produite en affectant à tous les champs de type valeur leur valeur par défaut et tous les champs de type référence à 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.

En faisant référence à la structure Point déclarée ci-dessus, l’exempleReferring to the Point struct declared above, the example

Point[] a = new Point[100];

Initialise chaque Point dans le tableau à la valeur produite en affectant la valeur zéro aux champs x et y.initializes each Point in the array to the value produced by setting the x and y fields to zero.

La valeur par défaut d’un struct correspond à la valeur retournée par le constructeur par défaut du struct (constructeurs par défaut).The default value of a struct corresponds to the value returned by the default constructor of the struct (Default constructors). Contrairement à une classe, un struct n’est pas autorisé à déclarer un constructeur d’instance sans paramètre.Unlike a class, a struct is not permitted to declare a parameterless instance constructor. Au lieu de cela, chaque struct a implicitement un constructeur d’instance sans paramètre qui retourne toujours la valeur qui résulte de l’affectation de la valeur par défaut à tous les champs de type de valeur et de l' null à tous les champs de type référence.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.

Les structs doivent être conçus pour considérer l’état d’initialisation par défaut comme un état valide.Structs should be designed to consider the default initialization state a valid state. Dans l’exempleIn 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;
    }
}

le constructeur d’instance défini par l’utilisateur est protégé contre les valeurs NULL uniquement lorsqu’il est appelé explicitement.the user-defined instance constructor protects against null values only where it is explicitly called. Dans les cas où une variable KeyValuePair est sujette à l’initialisation de la valeur par défaut, les champs key et value ont la valeur null, et la structure doit être préparée pour gérer cet État.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 et unboxingBoxing and unboxing

Une valeur d’un type de classe peut être convertie en type object ou en un type interface implémenté par la classe en traitant simplement la référence comme un autre type au moment de la compilation.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. De même, une valeur de type object ou une valeur d’un type d’interface peut être reconvertie en un type de classe sans modifier la référence (mais bien évidemment, une vérification de type au moment de l’exécution est requise dans ce cas).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).

Étant donné que les structs ne sont pas des types référence, ces opérations sont implémentées différemment pour les types struct.Since structs are not reference types, these operations are implemented differently for struct types. Quand une valeur d’un type struct est convertie en type object ou en un type interface implémenté par le struct, une opération boxing est effectuée.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. De même, lorsqu’une valeur de type object ou une valeur d’un type d’interface est convertie en type struct, une opération de conversion unboxing a lieu.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. Une différence essentielle par rapport aux mêmes opérations sur les types de classe est que le boxing et l’unboxing copient la valeur de struct à l’intérieur ou à l’extérieur de l’instance 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. Ainsi, à la suite d’une opération boxing ou unboxing, les modifications apportées au struct unboxed ne sont pas reflétées dans le struct boxed.Thus, following a boxing or unboxing operation, changes made to the unboxed struct are not reflected in the boxed struct.

Lorsqu’un type struct substitue une méthode virtuelle héritée de System.Object (comme Equals, GetHashCode ou ToString), l’appel de la méthode virtuelle via une instance du type struct ne provoque pas de conversion 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. Cela est vrai même lorsque le struct est utilisé comme paramètre de type et que l’appel se produit via une instance du type de paramètre de type.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. Exemple :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 sortie du programme est la suivante :The output of the program is:

1
2
3

Bien qu’il s’agisse d’un mauvais style pour ToString pour avoir des effets secondaires, l’exemple montre qu’aucune conversion boxing ne s’est produite pour les trois appels 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 même, le boxing ne se produit jamais implicitement lors de l’accès à un membre sur un paramètre de type restreint.Similarly, boxing never implicitly occurs when accessing a member on a constrained type parameter. Par exemple, supposons qu’une interface ICounter contient une méthode Increment qui peut être utilisée pour modifier une valeur.For example, suppose an interface ICounter contains a method Increment which can be used to modify a value. Si ICounter est utilisé en tant que contrainte, l’implémentation de la méthode Increment est appelée avec une référence à la variable sur laquelle Increment a été appelé, jamais une copie 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>();
    }
}

Le premier appel à Increment modifie la valeur dans la variable x.The first call to Increment modifies the value in the variable x. Cela n’est pas équivalent au deuxième appel à Increment, qui modifie la valeur dans une copie boxed de x.This is not equivalent to the second call to Increment, which modifies the value in a boxed copy of x. Ainsi, la sortie du programme est la suivante :Thus, the output of the program is:

0
1
1

Pour plus d’informations sur le boxing et l’unboxing, consultez conversion boxing et unboxing.For further details on boxing and unboxing, see Boxing and unboxing.

Signification de ceMeaning of this

Dans un constructeur d’instance ou un membre de fonction d’instance d’une classe, this est classée en tant que valeur.Within an instance constructor or instance function member of a class, this is classified as a value. Ainsi, bien que this puisse être utilisé pour faire référence à l’instance pour laquelle la fonction membre a été appelée, il n’est pas possible d’assigner à this dans une fonction membre d’une 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.

Dans un constructeur d’instance d’un struct, this correspond à un paramètre out du type struct, et dans une fonction membre d’instance d’un struct, this correspond à un paramètre ref du type 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. Dans les deux cas, this est classée en tant que variable et il est possible de modifier l’ensemble du struct pour lequel la fonction membre a été appelée en affectant à this ou en passant ce en tant que paramètre ref ou out.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.

Initialiseurs de champField initializers

Comme décrit dans valeurs par défaut, la valeur par défaut d’un struct se compose de la valeur qui résulte de l’affectation de la valeur par défaut à tous les champs de type de valeur et de l' null à tous les champs de type référence.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. Pour cette raison, un struct n’autorise pas les déclarations de champ d’instance à inclure des initialiseurs de variable.For this reason, a struct does not permit instance field declarations to include variable initializers. Cette restriction s’applique uniquement aux champs d’instance.This restriction applies only to instance fields. Les champs statiques d’un struct sont autorisés à inclure des initialiseurs de variable.Static fields of a struct are permitted to include variable initializers.

L’exempleThe example

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

est erroné, car les déclarations de champ d’instance incluent des initialiseurs de variable.is in error because the instance field declarations include variable initializers.

ConstructeursConstructors

Contrairement à une classe, un struct n’est pas autorisé à déclarer un constructeur d’instance sans paramètre.Unlike a class, a struct is not permitted to declare a parameterless instance constructor. Au lieu de cela, chaque struct a implicitement un constructeur d’instance sans paramètre qui retourne toujours la valeur qui résulte de l’affectation de la valeur par défaut à tous les champs de type de valeur et de tous les champs de type référence à la valeur null (constructeurs par défaut).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 peut déclarer des constructeurs d’instance ayant des paramètres.A struct can declare instance constructors having parameters. Exemple :For example

struct Point
{
    int x, y;

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

Compte tenu de la déclaration ci-dessus, les instructionsGiven the above declaration, the statements

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

les deux créent un Point avec x et y initialisé à zéro.both create a Point with x and y initialized to zero.

Un constructeur d’instance de struct n’est pas autorisé à inclure un initialiseur de constructeur de la forme base(...).A struct instance constructor is not permitted to include a constructor initializer of the form base(...).

Si le constructeur d’instance de struct ne spécifie pas d’initialiseur de constructeur, la variable this correspond à un paramètre out du type struct et est semblable à un paramètre out, this doit être assignée définitivement (assignation définie ) à chaque emplacement où le constructeur retourne.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 le constructeur d’instance de struct spécifie un initialiseur de constructeur, la variable this correspond à un paramètre ref du type struct et est semblable à un paramètre ref, this est considéré comme définitivement assigné à l’entrée dans le corps du constructeur .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. Examinez l’implémentation du constructeur d’instance ci-dessous :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
    }
}

Aucune fonction membre d’instance (y compris les accesseurs set des propriétés X et Y) ne peut être appelée tant que tous les champs du struct en cours de construction n’ont pas été définitivement assignés.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 seule exception concerne les propriétés implémentées automatiquement (Propriétés implémentées automatiquement).The only exception involves automatically implemented properties (Automatically implemented properties). Les règles d’assignation définie (expressions d’assignation simples) exemptent spécifiquement l’assignation à une propriété automatique d’un type struct dans un constructeur d’instance de ce type struct : une telle assignation est considérée comme une assignation définie du masqué champ de stockage de la propriété automatique.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. Ainsi, les éléments suivants sont autorisés :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
    }

DestructeursDestructors

Un struct n’est pas autorisé à déclarer un destructeur.A struct is not permitted to declare a destructor.

Constructeurs statiquesStatic constructors

Les constructeurs statiques pour les structs suivent la plupart des règles de la même façon que pour les classes.Static constructors for structs follow most of the same rules as for classes. L’exécution d’un constructeur statique pour un type struct est déclenchée par le premier des événements suivants pour se produire au sein d’un domaine d’application :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:

  • Un membre statique du type struct est référencé.A static member of the struct type is referenced.
  • Un constructeur déclaré explicitement du type struct est appelé.An explicitly declared constructor of the struct type is called.

La création de valeurs par défaut (valeurs par défaut) de types struct ne déclenche pas le constructeur statique.The creation of default values (Default values) of struct types does not trigger the static constructor. (Par exemple, il s’agit de la valeur initiale des éléments d’un tableau).(An example of this is the initial value of elements in an array.)

Exemples de structStruct examples

L’exemple suivant montre deux exemples significatifs de l’utilisation de types struct pour créer des types qui peuvent être utilisés de la même manière que les types prédéfinis du langage, mais avec la sémantique modifiée.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.

Type d’entier de base de donnéesDatabase integer type

Le struct DBInt ci-dessous implémente un type entier qui peut représenter l’ensemble complet des valeurs du type int, ainsi qu’un État supplémentaire qui indique une valeur inconnue.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 type avec ces caractéristiques est couramment utilisé dans les bases de données.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";
    }
}

Type booléen de base de donnéesDatabase boolean type

Le struct DBBool ci-dessous implémente un type logique à trois valeurs.The DBBool struct below implements a three-valued logical type. Les valeurs possibles de ce type sont DBBool.True, DBBool.False et DBBool.Null, où le membre Null indique une valeur inconnue.The possible values of this type are DBBool.True, DBBool.False, and DBBool.Null, where the Null member indicates an unknown value. Ces types logiques à trois valeurs sont couramment utilisés dans les bases de données.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";
    }
}