¿Cuándo usas la palabra clave “this”?

Tenía curiosidad sobre cómo otras personas usan la palabra clave this . Tiendo a usarlo en constructores, pero también puedo usarlo en toda la clase en otros métodos. Algunos ejemplos:

En un constructor:

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

En otra parte

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

Hay varios usos de esta palabra clave en C #.

  1. Para calificar miembros ocultos por un nombre similar
  2. Tener un objeto que se pase como un parámetro para otros métodos
  3. Para que un objeto se devuelva a sí mismo desde un método
  4. Para declarar indexadores
  5. Para declarar métodos de extensión
  6. Para pasar parámetros entre constructores
  7. Para reasignar internamente el valor del tipo de valor (struct) .
  8. Para invocar un método de extensión en la instancia actual
  9. Para lanzarse a otro tipo
  10. Para encadenar constructores definidos en la misma clase

Puede evitar el primer uso al no tener variables miembro y locales con el mismo nombre en el scope, por ejemplo, siguiendo convenciones de nomenclatura comunes y utilizando propiedades (caso Pascal) en lugar de campos (caso camel) para evitar colisiones con variables locales (también camello) caso). En C # 3.0, los campos se pueden convertir fácilmente en propiedades mediante el uso de propiedades implementadas automáticamente .

No me refiero a que esto suene sarcástico, pero no importa.

Seriamente.

Mire las cosas que son importantes: su proyecto, su código, su trabajo, su vida personal. Ninguno de ellos va a tener su éxito en descansar si usa o no la palabra clave “this” para calificar el acceso a los campos. La palabra clave this no te ayudará a enviar a tiempo. No va a reducir los errores, no va a tener un efecto apreciable en la calidad del código o el mantenimiento. No va a conseguir un aumento o le permitirá pasar menos tiempo en la oficina.

Es solo un problema de estilo. Si te gusta “esto”, entonces úsalo. Si no lo haces, entonces no lo hagas. Si lo necesita para obtener la semántica correcta, entonces úselo. La verdad es que cada progtwigdor tiene su propio estilo de progtwigción único. Ese estilo refleja las nociones de ese progtwigdor particular sobre cómo debería ser el “código más estéticamente agradable”. Por definición, cualquier otro progtwigdor que lea su código tendrá un estilo de progtwigción diferente. Eso significa que siempre habrá algo que hayas hecho que al otro no le guste, o que hubiera hecho de manera diferente. En algún momento, algún tipo leerá tu código y se quejará de algo.

No me preocuparía por eso. Solo me aseguraría de que el código sea lo más estético posible según tus propios gustos. Si le preguntas a 10 progtwigdores cómo formatear el código, obtendrás unas 15 opiniones diferentes. Una mejor cosa en que enfocarse es cómo se tiene en cuenta el código. ¿Las cosas se resumen bien? ¿Escogí nombres significativos para las cosas? ¿Hay mucha duplicación de código? ¿Hay formas en que puedo simplificar cosas? Hacer las cosas bien, creo, tendrá el mayor impacto positivo en su proyecto, su código, su trabajo y su vida. Casualmente, probablemente también hará que el otro tipo se queje menos. Si su código funciona, es fácil de leer y está bien factorizado, el otro no va a analizar cómo inicializar los campos. Simplemente usará tu código, se maravillará con su grandeza y luego pasará a otra cosa.

Solo lo uso cuando es absolutamente necesario, es decir, cuando otra variable está sombreando a otra. Tal como aquí:

 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; } } 

O como lo señala Ryan Fox, cuando necesitas pasar esto como un parámetro. (Las variables locales tienen prioridad sobre las variables miembro)

Personalmente, trato de usarlo siempre cuando me refiero a las variables miembro. Ayuda a aclarar el código y hacerlo más legible. Incluso si no hay ambigüedad, alguien que lea mi código por primera vez no lo sabe, pero si lo utilizan de manera consistente, sabrán si están viendo una variable miembro o no.

No puedo creer que todas las personas que dicen usarlo siempre sean una “mejor práctica” y tal.

Use “esto” cuando haya ambigüedad, como en el ejemplo de Corey o cuando necesite pasar el objeto como un parámetro, como en el ejemplo de Ryan . No hay ninguna razón para usarlo de otra manera porque poder resolver una variable basada en la cadena de scope debería ser lo suficientemente claro como para que las variables calificadas con él sean innecesarias.

EDIT: la documentación de C # en “this” indica un uso más, además de los dos que mencioné, para la palabra clave “this” – para declarar indexadores

EDITAR: @Juan: Huh, no veo ninguna incoherencia en mis declaraciones: hay 3 instancias en las que usaría la palabra clave “this” (como se documenta en la documentación de C #), y esas son ocasiones en las que realmente la necesita . Poner “esto” delante de las variables en un constructor cuando no hay sombreado es simplemente un desperdicio de teclas y una pérdida de tiempo al leerlo, no proporciona ningún beneficio.

Lo uso cada vez que me refiero a una variable de instancia, incluso si no es necesario. Creo que hace que el código sea más claro.

Lo uso cada vez que StyleCop me lo dice. StyleCop debe ser obedecido. Oh si.

Cada vez que necesite una referencia al objeto actual.

Un escenario particularmente útil es cuando su objeto llama a una función y quiere pasar a ella.

Ejemplo:

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

Tiendo a usarlo en todas partes también, solo para asegurarme de que está claro que estamos tratando con los miembros de la instancia.

Lo uso en cualquier lugar donde pueda haber ambigüedad (obviamente). No solo la ambigüedad del comstackdor (se requeriría en ese caso), sino también la ambigüedad para alguien que mira el código.

Otro uso algo raro para esta palabra clave es cuando necesita invocar una implementación de interfaz explícita desde dentro de la clase implementadora. Aquí hay un ejemplo artificial:

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

Aquí es cuando lo uso:

  • Accediendo a métodos privados desde dentro de la clase (para diferenciar)
  • Pasar el objeto actual a otro método (o como un objeto remitente, en caso de un evento)
  • Al crear métodos de extensión: D

No uso esto para los campos privados porque prefijo los nombres de las variables de campo privadas con un guión bajo (_).

[C ++]

Estoy de acuerdo con la brigada “úsala cuando sea necesario”. Decorar el código innecesariamente con esto no es una gran idea porque el comstackdor no lo advertirá cuando lo olvide. Esto introduce confusión potencial para las personas que esperan que esto siempre esté allí, es decir, tendrán que pensar en ello.

Entonces, ¿cuándo lo usarías? Acabo de echar un vistazo a un código al azar y encontré estos ejemplos (no estoy juzgando si estas cosas son buenas o no):

  • Pasar “usted mismo” a una función.
  • Asignar “usted mismo” a un puntero o algo así.
  • Fundición, es decir, fundición arriba / abajo (segura o no), fundición de constness, etc.
  • Desambiguación forzada por el comstackdor.

Lo uso cuando, en una función que acepta una referencia a un objeto del mismo tipo, quiero dejar perfectamente en claro a qué objeto me refiero, dónde.

Por ejemplo

 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() ; } } ; 

(vs)

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

A simple vista, lo que AABB hace right() refiere a? this agrega un poco de clarificador.

En la respuesta de Jakub Šturc, su # 5 sobre pasar datos entre contructors probablemente podría usar una pequeña explicación. Esto está en sobrecarga de constructores y es el único caso donde el uso de this es obligatorio. En el siguiente ejemplo, podemos llamar al constructor parametrizado desde el constructor sin parámetros con un parámetro predeterminado.

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

He encontrado que esta es una característica particularmente útil en ocasiones.

Siempre debe usarlo, lo uso para diferenciar campos y parámetros privados (porque nuestras convenciones de nombres indican que no usamos prefijos para nombres de miembros y parámetros (y se basan en información que se encuentra en Internet, por lo que considero que un mejores prácticas))

Adquirí el hábito de usarlo liberalmente en Visual C ++ ya que hacerlo activaría los IntelliSense, presioné la tecla ‘>’ y soy flojo. (y propenso a errores tipográficos)

Pero he seguido usándolo, ya que me resulta útil ver que estoy llamando a una función miembro en lugar de una función global.

Tiendo a subrayar campos con _ así que realmente nunca necesito usar esto. También R # tiende a refactorizarlos de todos modos …

Casi solo uso esto cuando hago referencia a una propiedad de tipo dentro del mismo tipo. Como mencionó otro usuario, también hago hincapié en los campos locales para que se noten sin necesidad de esto .

Lo uso solo cuando es necesario, excepto para las operaciones simétricas que, debido a un polymorphism de argumento único, tienen que ponerse en los métodos de un lado:

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

[C ++]

esto se usa en el operador de asignación donde la mayoría de las veces tiene que verificar y evitar cosas extrañas (involuntarias, peligrosas o simplemente una pérdida de tiempo para el progtwig) tales como:

 A a; a = a; 

Su operador de asignación será escrito:

 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 en un comstackdor de C ++

El comstackdor C ++ buscará silenciosamente un símbolo si no lo encuentra de inmediato. A veces, la mayoría de las veces, es bueno:

  • usando el método de la clase de madre si no lo sobrecargó en la clase de niño.
  • promoviendo un valor de un tipo en otro tipo

Pero a veces, simplemente no quieres que el comstackdor adivine. Quiere que el comstackdor recoja el símbolo correcto y no otro.

Para mí , esos momentos son cuando, dentro de un método, quiero acceder a un método miembro o una variable miembro. Simplemente no quiero que se recoja algún símbolo aleatorio solo porque escribí printf lugar de print . this->printf no se habría comstackdo.

El punto es que, con las bibliotecas heredadas de C (§), código heredado escrito hace años (§§), o lo que pueda suceder en un idioma donde copiar / pegar es una característica obsoleta pero activa, a veces, diciéndole al comstackdor que no juegue ingenio es una gran idea.

Estas son las razones por las que uso this .

(§) sigue siendo una especie de misterio para mí, pero ahora me pregunto si el hecho de incluir el encabezado en su fuente es la razón por la cual todos los símbolos heredados de las bibliotecas C contaminarán su espacio de nombres global.

(§§) al darse cuenta de que “necesita incluir un encabezado, pero que incluir este encabezado romperá su código porque usa una macro tonta con un nombre genérico” es uno de esos momentos de la ruleta rusa de la vida de un codificador

Lo uso para invocar Intellisense como JohnMcG , pero volveré y borraré “this->” cuando haya terminado. Sigo la convención de Microsoft de prefijar variables miembro con “m_”, por lo que dejarlo como documentación sería redundante.

‘esta.’ ayuda a encontrar miembros en esta clase con muchos miembros (generalmente debido a una cadena de herencia profunda).

Pulsar CTRL + Espacio no ayuda con esto, porque también incluye tipos; donde-como ‘esto’. incluye miembros SOLAMENTE.

Normalmente lo borro una vez que tengo lo que buscaba: pero este es solo mi estilo.

En términos de estilo, si eres un vigilante solitario, tú decides; si trabajas para una empresa, cumple con la política de la empresa (mira lo que está en control de fuente y observa lo que otras personas están haciendo). En términos de usarlo para calificar a los miembros, ninguno es correcto o incorrecto. Lo único incorrecto es la inconsistencia: esa es la regla de oro del estilo. Deja a los demás recoger los insectos. Dedique su tiempo a reflexionar sobre los problemas reales de encoding, y obviamente la encoding, en su lugar.

Depende del estándar de encoding en el que estoy trabajando. Si estamos usando _ para denotar una variable de instancia, entonces “this” se vuelve redundante. Si no estamos usando _ entonces tiendo a usar esto para denotar la variable de instancia.

1 – Idioma del setter común de Java:

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

2 – Cuando se llama a una función con este objeto como parámetro

 notifier.addListener(this); 

Lo uso cada vez que puedo. Creo que hace que el código sea más legible, y un código más legible equivale a menos errores y más capacidad de mantenimiento.

Cuando hay muchos desarrolladores trabajando en la misma base de código, necesita algunas pautas / reglas de código. Donde trabajo, deseamos usar ‘esto’ en campos, propiedades y eventos.

Para mí tiene sentido hacerlo así, hace que el código sea más fácil de leer cuando diferencias entre variables de clase y variables de método.

Hay un uso que no se ha mencionado anteriormente en C ++, y eso no es referirse al propio objeto o desambiguar a un miembro de una variable recibida.

Puede usar this para convertir un nombre no dependiente en un nombre dependiente de argumento dentro de clases de plantilla que hereden de otras plantillas.

 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 } } 

Las plantillas se comstackn con un mecanismo de dos pasadas. Durante la primera pasada, solo los nombres que no dependen de los argumentos se resuelven y se verifican, mientras que los nombres dependientes se comprueban solo por coherencia, sin sustituir realmente los argumentos de la plantilla.

En ese paso, sin sustituir realmente el tipo, el comstackdor casi no tiene información de qué base podría ser (tenga en cuenta que la especialización de la plantilla base puede convertirlo en tipos completamente diferentes, incluso en tipos no definidos), por lo que simplemente supone que es un tipo. En esta etapa, la llamada no dependiente f que parece natural para el progtwigdor es un símbolo que el comstackdor debe encontrar como miembro de los espacios de nombres derived o adjuntos, lo que no sucede en el ejemplo, y se quejará.

La solución está convirtiendo el nombre no dependiente f en un nombre dependiente. Esto se puede hacer de dos maneras, indicando explícitamente el tipo en el que se implementa ( base::f –agregando la base hace que el símbolo dependa de T y el comstackdor simplemente asumirá que lo hará existe y pospone el cheque real para el segundo pase, después de la sustitución del argumento.

La segunda forma, mucho sorter si heredas de plantillas que tienen más de un argumento, o nombres largos, es simplemente agregar un this-> antes del símbolo. Como la clase de plantilla que está implementando depende de un argumento (hereda de base ) this-> depende del argumento, y obtenemos el mismo resultado: this->f se comprueba en la segunda ronda, después de la sustitución del parámetro de la plantilla .

No debe usar “esto” a menos que sea absolutamente necesario.

HAY una penalización asociada con una verbosidad innecesaria. Debes esforzarte por obtener un código que sea exactamente el tiempo que debe ser y ya no lo es.