64 votes

Modification de la variable "this" des types de valeurs

Apparemment, vous pouvez changer le this de n'importe où dans votre structure (mais pas dans les classes) :

struct Point
{
    public Point(int x, int y)
    {
        this = new Point();
        X = x; Y = y;
    }
    int X; int Y;
}

Je n'ai jamais vu cela auparavant et je n'en ai jamais eu besoin. Pourquoi voudrait-on faire ça ? Eric Lippert nous rappelle qu'une fonctionnalité doit être justifiée pour être mise en œuvre. Quel grand cas d'utilisation pourrait justifier cela ? Existe-t-il des scénarios où cela est inestimable ? Je n'ai pas trouvé de documentation à ce sujet 1 .

En outre, pour appeler les constructeurs, il existe déjà une syntaxe alternative mieux connue, de sorte que cette fonctionnalité est parfois redondante :

public Point(int x, int y)
    : this()
{
    X = x; Y = y;
}

J'ai trouvé cette fonctionnalité dans un exemple de l'ouvrage de Jeffrey Richter intitulé <a href="http://rads.stackoverflow.com/amzn/click/0735667454">CLR via C# 4ème édition </a>.
1) Apparemment, c'est dans le <a href="http://stackoverflow.com/a/14767499/146622">Spécification C# </a>.

54voto

Eric Lippert Points 300275

Bonne question !

Les types de valeurs sont, par définition, copiés par valeur. Si this n'était pas en fait un alias vers un emplacement de stockage alors le constructeur initialiserait une copie plutôt que d'initialiser la variable que vous souhaitez initialiser. Ce qui rendrait le constructeur plutôt moins utile ! Et de même pour les méthodes ; oui, les structures mutables sont diaboliques mais si vous voulez faire une structure mutable, alors encore une fois, this doit être la variable qui est mutée, et non une copie de sa valeur.

Le comportement que vous décrivez est une conséquence logique de cette décision de conception : puisque this alias une variable, vous pouvez lui assigner, de la même manière que vous pouvez assigner à n'importe quelle autre variable.

Il est quelque peu étrange d'assigner directement à this comme ça, plutôt que d'assigner à ses champs. Il est encore plus étrange d'assigner directement à this et ensuite écraser 100% de cette affectation !

Une conception alternative qui éviterait de faire this un alias pour le stockage du récepteur serait d'allouer this du pool de stockage à court terme, l'initialiser dans le ctor, puis le retourner par valeur. L'inconvénient de cette approche est qu'elle rend les optimisations d'élision de copie pratiquement impossibles, et qu'elle rend les ctors et les méthodes étrangement incohérents.

10voto

Damien_The_Unbeliever Points 102139

De plus, je n'ai pas trouvé de documentation à ce sujet.

Avez-vous essayé de regarder dans la spécification C# ? Parce que je peux trouver de la documentation à ce sujet (7.6.7) :

  • Quand this est utilisé dans un expression primaire dans un constructeur d'instance d'une structure, il est classé comme une variable. Le type de la variable est le type d'instance (§10.3.1) de la structure dans laquelle l'utilisation a lieu, et la variable représente la structure en cours de construction. Le site this d'un constructeur d'instance d'un struct se comporte exactement de la même manière qu'une variable out du type struct - en particulier, cela signifie que la variable doit être définitivement assignée dans chaque chemin d'exécution du constructeur d'instance.

  • Quand this est utilisé dans un expression primaire dans une méthode d'instance ou un accesseur d'instance d'une structure, il est classé comme une variable. Le type de la variable est le type d'instance (§10.3.1) de la structure dans laquelle l'utilisation a lieu.

    • Si la méthode ou l'accesseur n'est pas un itérateur (§10.14), l'attribut this représente la structure pour laquelle la méthode ou l'accesseur a été invoqué, et se comporte exactement de la même manière qu'une variable ref du paramètre du type struct.
    • Si la méthode ou l'accesseur est un itérateur, la balise this représente une copie de la structure pour laquelle la méthode ou l'accesseur a été invoqué, et se comporte exactement de la même manière que la variable valeur du paramètre du type struct.

Pour ce qui est de son utilisation, je n'en vois pas beaucoup - la seule chose que j'ai en tête est si les valeurs que vous voulez assigner dans le constructeur sont coûteuses à calculer, et que vous avez une valeur en cache que vous voulez copier dans le fichier this ça pourrait être pratique.

0voto

supercat Points 25534

Un emplacement de stockage de type valeur dans une agrégation d'emplacements de stockage comprenant les champs publics et privés de ce type. Le passage d'un type de valeur en tant que paramètre ordinaire (valeur) transmet physiquement et sémantiquement le contenu de tous ses champs. Le passage d'un type de valeur en tant que ref transmet sémantiquement le contenu de tous ses champs, bien qu'un seul "byref" soit utilisé pour les transmettre tous.

L'appel d'une méthode sur un struct est équivalent au passage du struct (et donc de tous ses champs) en tant qu'objet de type ref à un détail près : normalement, ni C# ni vb.net n'autorisent le passage d'une valeur en lecture seule en tant que paramètre ref paramètre. Cependant, les deux permettent d'invoquer des méthodes struct sur des valeurs en lecture seule ou des valeurs temporaires. Pour ce faire, ils effectuent une copie de la structure (et donc de tous ses champs), puis transmettent cette copie en tant que paramètre de type ref paramètre.

À cause de ce comportement, certaines personnes qualifient les structures mutables de "diaboliques", mais la seule chose qui est diabolique est le fait que ni C# ni vb.net ne définissent d'attribut pour indiquer si un membre ou une propriété de structure doit être invocable sur des choses qui ne peuvent pas être passées directement par ref .

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X