Quand utilisez-vous le mot-clé «this»?

J’étais curieux de savoir comment d’autres personnes utilisent ce mot clé. J’ai tendance à l’utiliser dans les constructeurs, mais je peux aussi l’utiliser dans toute la classe avec d’autres méthodes. Quelques exemples:

Dans un constructeur:

public Light(Vector v) { this.dir = new Vector(v); } 

Autre part

 public void SomeMethod() { Vector vec = new Vector(); double d = (vec * vec) - (this.radius * this.radius); } 

Il existe plusieurs utilisations de ce mot clé en C #.

  1. Pour qualifier les membres cachés par un nom similaire
  2. Pour qu’un object se transmette en paramètre à d’autres méthodes
  3. Pour qu’un object retourne lui-même d’une méthode
  4. Déclarer des indexeurs
  5. Pour déclarer des méthodes d’extension
  6. Passer des parameters entre constructeurs
  7. Pour réaffecter en interne la valeur du type de valeur (struct) .
  8. Pour appeler une méthode d’extension sur l’instance actuelle
  9. Se lancer dans un autre type
  10. Pour enchaîner des constructeurs définis dans la même classe

Vous pouvez éviter la première utilisation en ne disposant pas de variables membres et locales portant le même nom, en respectant par exemple les conventions de dénomination communes et en utilisant les propriétés (cas Pascal) au lieu des champs (cas camel). Cas). Dans C # 3.0, les champs peuvent être facilement convertis en propriétés en utilisant des propriétés implémentées automatiquement .

Je ne veux pas dire ça pour sonner, mais ça n’a pas d’importance.

Sérieusement.

Regardez les choses importantes: votre projet, votre code, votre travail, votre vie personnelle. Aucun d’entre eux ne va réussir à savoir si vous utilisez le mot-clé “this” pour qualifier l’access aux champs. Ce mot-clé ne vous aidera pas à expédier à temps. Cela ne va pas réduire les bogues, cela ne va pas avoir d’effet appréciable sur la qualité du code ou la maintenabilité. Cela ne va pas vous amener une augmentation ou vous permettre de passer moins de temps au bureau.

C’est vraiment un problème de style. Si vous aimez “ceci”, alors utilisez-le. Si vous ne le faites pas, alors ne le faites pas. Si vous en avez besoin pour obtenir une sémantique correcte, utilisez-la. La vérité est que chaque programmeur a son propre style de programmation. Ce style reflète les notions de ce programmeur particulier sur ce à quoi devrait ressembler le “code le plus esthétique”. Par définition, tout autre programmeur qui lit votre code va avoir un style de programmation différent. Cela signifie qu’il y aura toujours quelque chose que l’autre gars n’aime pas ou aurait fait différemment. A un moment, un gars va lire votre code et se plaindre de quelque chose.

Je ne m’inquiéterais pas pour ça. Je voudrais juste m’assurer que le code est aussi esthétique que possible selon vos propres goûts. Si vous demandez à 10 programmeurs comment formater le code, vous obtiendrez environ 15 avis différents. Il est préférable de se concentrer sur la manière dont le code est pris en compte. Les choses sont-elles abstraites? Ai-je choisi des noms significatifs pour les choses? Y a-t-il beaucoup de duplication de code? Y a-t-il des moyens de simplifier les choses? Je pense que bien faire les choses aura le plus grand impact positif sur votre projet, votre code, votre travail et votre vie. Par coïncidence, cela va probablement aussi faire grogner le moindre des gars. Si votre code fonctionne, est facile à lire et est bien pris en compte, l’autre ne va pas scruter la façon dont vous initialisez les champs. Il va juste utiliser votre code, s’émerveiller de sa grandeur et passer ensuite à autre chose.

Je ne l’utilise que lorsque c’est absolument nécessaire, c.-à-d. Quand une autre variable suit une autre. Comme ici:

 class Vector3 { float x; float y; float z; public Vector3(float x, float y, float z) { this.x = x; this.y = y; this.z = z; } } 

Ou, comme le souligne Ryan Fox, lorsque vous devez passer ceci en paramètre. (Les variables locales ont priorité sur les variables membres)

Personnellement, j’essaie de toujours utiliser cela en me référant aux variables membres. Cela aide à clarifier le code et à le rendre plus lisible. Même s’il n’y a pas d’ambiguïté, quelqu’un qui lit pour la première fois mon code ne le sait pas, mais s’il le voit régulièrement, il saura s’il regarde une variable membre ou non.

Je ne peux pas croire que toutes les personnes qui disent que l’utiliser est toujours une «pratique exemplaire».

Utilisez “this” lorsqu’il y a une ambiguïté, comme dans l’exemple de Corey ou lorsque vous devez passer l’object en tant que paramètre, comme dans l’exemple de Ryan . Il n’y a aucune raison de l’utiliser autrement, car la possibilité de résoudre une variable en fonction de la chaîne de scope doit être suffisamment claire pour que la qualification des variables avec celle-ci soit inutile.

EDIT: La documentation C # sur “this” indique une autre utilisation, à part les deux que j’ai mentionnées, pour le mot clé “this” – pour déclarer des indexeurs

EDIT: @Juan: Hein, je ne vois aucune incohérence dans mes déclarations – il y a 3 cas où j’utiliserais le mot-clé “this” (comme documenté dans la documentation C #), et ce sont des moments où vous en avez réellement besoin . Coller “ceci” devant des variables dans un constructeur quand il n’y a pas de filature est simplement un gaspillage de frappes de touches et une perte de temps en le lisant, cela n’apporte aucun avantage.

Je l’utilise chaque fois que je me réfère à une variable d’instance, même si je n’en ai pas besoin. Je pense que cela rend le code plus clair.

Je l’utilise quand StyleCop me dit de le faire. StyleCop doit être respecté. Oh oui.

Chaque fois que vous avez besoin d’une référence à l’object actuel.

Un scénario particulièrement pratique est celui où votre object appelle une fonction et veut y entrer.

Exemple:

 void onChange() { screen.draw(this); } 

J’ai tendance à l’utiliser partout, simplement pour m’assurer qu’il est clair que ce sont les membres de l’instance avec lesquels nous traitons.

Je l’utilise partout où il peut y avoir une ambiguïté (évidemment). Pas seulement l’ambiguïté du compilateur (il serait nécessaire dans ce cas), mais aussi l’ambiguïté pour quelqu’un qui regarde le code.

Une autre utilisation quelque peu rare de ce mot-clé est lorsque vous devez appeler une implémentation d’interface explicite depuis la classe d’implémentation. Voici un exemple:

 class Example : ICloneable { private void CallClone() { object clone = ((ICloneable)this).Clone(); } object ICloneable.Clone() { throw new NotImplementedException(); } } 

Voici quand je l’utilise:

  • Accéder aux méthodes privées depuis la classe (différencier)
  • Passer l’object actuel à une autre méthode (ou en tant qu’object émetteur, en cas d’événement)
  • Lors de la création de méthodes d’extension: D

Je ne l’utilise pas pour les champs privés, car je préfixe les noms de variables de champs privés avec un trait de soulignement (_).

[C ++]

Je suis d’accord avec la “utiliser quand il faut” la brigade. Décorer le code inutilement avec ceci n’est pas une bonne idée car le compilateur ne vous avertira pas lorsque vous oubliez de le faire. Cela introduit une confusion potentielle pour les personnes qui s’attendent à ce qu’elles soient toujours présentes, c’est-à-dire qu’elles devront y réfléchir .

Alors, quand l’utiliseriez-vous? Je viens de jeter un coup d’oeil autour d’un code aléatoire et j’ai trouvé ces exemples (je ne suis pas en train de dire si ce sont de bonnes choses à faire ou non):

  • Passer “toi-même” à une fonction.
  • Assigner “vous-même” à un pointeur ou quelque chose comme ça.
  • Coulée, c.-à-d. Coulée en haut / bas (sûre ou non), jetant la constance, etc.
  • La désambiguïsation forcée du compilateur.

Je l’utilise lorsque, dans une fonction qui accepte une référence à un object du même type, je veux préciser clairement à quel object je me réfère, où.

Par exemple

 class AABB { // ... members bool intersects( AABB other ) { return other.left() < this->right() && this->left() < other.right() && // +y increases going down other.top() < this->bottom() && this->top() < other.bottom() ; } } ; 

(contre)

 class AABB { bool intersects( AABB other ) { return other.left() < right() && left() < other.right() && // +y increases going down other.top() < bottom() && top() < other.bottom() ; } } ; 

D'un coup d'œil, à quoi AABB a-t-il right() ? this ajoute un peu de clarificateur.

Dans la réponse de Jakub Šturc, son numéro 5 sur le passage des données entre les entrepreneurs pourrait probablement utiliser une petite explication. C’est dans la surcharge des constructeurs et c’est le cas où l’utilisation de this est obligatoire. Dans l’exemple suivant, nous pouvons appeler le constructeur paramétré à partir du constructeur sans paramètre avec un paramètre par défaut.

 class MyClass { private int _x public MyClass() : this(5) {} public MyClass(int v) { _x = v;} } 

J’ai trouvé cette fonctionnalité particulièrement utile à l’occasion.

Vous devez toujours l’utiliser, je l’utilise pour différencier les champs et parameters privés (car nos conventions de nommage stipulent que nous n’utilisons pas de préfixes pour les noms de membre et de paramètre (et qu’ils sont basés sur des informations trouvées sur Internet). meilleur entrainement))

J’ai pris l’habitude de l’utiliser largement dans Visual C ++ car cela déclencherait ceux d’IntelliSense que j’appuyais sur la touche ‘>’ et je suis paresseux. (et sujettes aux fautes de frappe)

Mais j’ai continué à l’utiliser, car je trouve pratique de voir que j’appelle une fonction membre plutôt qu’une fonction globale.

J’ai tendance à souligner les champs avec _ donc je n’ai jamais vraiment besoin de l’utiliser. De plus, R # a tendance à les réorganiser de toute façon …

Je ne l’utilise que pour référencer une propriété de type du même type. Comme un autre utilisateur l’a mentionné, je souligne également les champs locaux afin qu’ils soient perceptibles sans cela .

Je ne l’utilise que lorsque cela est nécessaire, sauf pour les opérations symésortingques qui, en raison d’un polymorphism d’argument unique, doivent être mises en œuvre dans des méthodes d’un côté:

 boolean sameValue (SomeNum other) { return this.importantValue == other.importantValue; } 

[C ++]

Ceci est utilisé dans l’opérateur d’affectation où la plupart du temps, vous devez vérifier et prévenir des événements étranges (involontaires, dangereux ou simplement une perte de temps pour le programme), tels que:

 A a; a = a; 

Votre opérateur d’affectation sera écrit:

 A& A::operator=(const A& a) { if (this == &a) return *this; // we know both sides of the = operator are different, do something... return *this; } 

this sur un compilateur C ++

Le compilateur C ++ recherchera silencieusement un symbole s’il ne le trouve pas immédiatement. Parfois, la plupart du temps, c’est bien:

  • en utilisant la méthode de la classe mère si vous ne l’avez pas surchargée dans la classe enfant.
  • promouvoir une valeur d’un type dans un autre type

Mais parfois, vous ne voulez simplement pas que le compilateur devine. Vous voulez que le compilateur prenne le bon symbole et pas un autre.

Pour moi , ces moments sont ceux où, dans une méthode, je veux accéder à une méthode membre ou à une variable membre. Je ne veux tout simplement pas qu’un symbole aléatoire soit capté juste parce que j’ai écrit printf au lieu de print . this->printf n’aurait pas été compilé.

Le fait est que, avec les bibliothèques héritées C (§), le code hérité écrit il ya des années (§§), ou tout ce qui peut arriver dans une langue où le copier / coller est une fonctionnalité obsolète mais toujours active. l’esprit est une excellente idée.

Ce sont les raisons pour lesquelles je l’utilise.

(§) c’est toujours une sorte de mystère pour moi, mais je me demande maintenant si le fait d’inclure l’en-tête dans votre source est la raison pour laquelle tous les symboles de bibliothèques C anciens pollueront votre espace de noms global

(§§) se rendant compte que “vous devez inclure un en-tête, mais que l’inclusion de cet en-tête va casser votre code parce qu’il utilise une macro idiote avec un nom générique” est l’un de ces moments de roulette russe

Je l’utilise pour invoquer Intellisense comme JohnMcG , mais je vais revenir en arrière et effacer “this->” quand j’ai fini. Je suis la convention de Microsoft de préfixer les variables membres avec “m_”, donc le laisser comme documentation serait simplement redondant.

‘ce.’ aide à trouver des membres dans cette classe avec beaucoup de membres (généralement en raison d’une chaîne d’inheritance profonde).

Frapper CTRL + Espace n’aide pas avec cela, car il inclut également les types; où-comme «ceci» comprend des membres UNIQUEMENT.

Je le supprime habituellement une fois que j’ai ce que j’ai été après: mais c’est juste mon style qui traverse.

En termes de style, si vous êtes un garde isolé, vous décidez; si vous travaillez pour une entreprise, respectez la politique de l’entreprise (examinez le contenu du contrôle des sources et voyez ce que font les autres). En termes d’utilisation pour qualifier les membres, ce n’est ni vrai ni faux. La seule mauvaise chose est l’incohérence – c’est la règle d’or du style. Laissez les autres piéger. Passez votre temps à réfléchir à de vrais problèmes de codage – et bien sûr au codage – à la place.

Cela dépend de la norme de codage dans laquelle je travaille. Si nous utilisons _ pour désigner une variable d’instance, alors “this” devient redondant. Si nous n’utilisons pas _, j’ai tendance à utiliser ceci pour désigner une variable d’instance.

1 – idiome commun du setter Java:

  public void setFoo(int foo) { this.foo = foo; } 

2 – Lors de l’appel d’une fonction avec cet object en tant que paramètre

 notifier.addListener(this); 

Je l’utilise chaque fois que je peux. Je crois que cela rend le code plus lisible et un code plus lisible équivaut à moins de bogues et à plus de facilité de maintenance.

Lorsque vous êtes de nombreux développeurs travaillant sur la même base de code, vous avez besoin de règles / règles. Là où je travaille, nous avons décidé d’utiliser «this» sur les champs, les propriétés et les événements.

Pour moi, il est logique de le faire comme ça, cela facilite la lecture du code lorsque vous faites la distinction entre les variables de classe et les variables de méthode.

Il y a une utilisation qui n’a pas déjà été mentionnée en C ++, et qui ne consiste pas à faire référence au propre object ou à ne pas désambiguïser un membre d’une variable reçue.

Vous pouvez l’utiliser pour convertir un nom non dépendant en un nom dépendant de l’argument à l’intérieur des classes de modèle qui héritent d’autres modèles.

 template  struct base { void f() {} }; template  struct derived : public base { void test() { //f(); // [1] error base::f(); // quite verbose if there is more than one argument, but valid this->f(); // f is now an argument dependent symbol } } 

Les modèles sont compilés avec un mécanisme à deux passages. Au cours de la première passe, seuls les noms dépendants non-argument sont résolus et vérifiés, tandis que les noms dépendants ne sont vérifiés que pour la cohérence, sans pour autant remplacer les arguments du modèle.

À cette étape, sans pour autant remplacer le type, le compilateur n’a quasiment aucune information sur ce que pourrait être la base (notez que la spécialisation du modèle de base peut en faire des types complètement différents, même des types non définis). c’est un type. A ce stade, l’appel non dépendant f qui semble naturel pour le programmeur est un symbole que le compilateur doit trouver en tant que membre des espaces de noms derived ou englobants – ce qui ne se produit pas dans l’exemple – et il se plaindra.

La solution transforme le nom non dépendant f en un nom dépendant. Cela peut être fait de plusieurs manières, en indiquant explicitement le type où il est implémenté ( base::f ajoutant la base rend le symbole dépendant de T et le compilateur supposera simplement qu’il le fera). existe et reporte la vérification réelle de la seconde passe, après la substitution des arguments.

La seconde manière, beaucoup de sortinger si vous héritez de modèles qui ont plus d’un argument, ou de noms longs, consiste à append un this-> avant le symbole. Comme la classe de modèle que vous implémentez dépend d’un argument (il hérite de la base ), this-> dépend des arguments, et nous obtenons le même résultat: this->f est vérifié au second tour, après la substitution des parameters du modèle .

Vous ne devez pas utiliser “this” sauf si vous devez absolument le faire.

Il y a une pénalité associée à la verbosité inutile. Vous devez vous efforcer d’obtenir du code qui soit exactement aussi long que nécessaire, et non plus.