¿Cuándo utiliza la palabra clave "esto"? [cerrado]

249

Tenía curiosidad acerca de cómo otras personas usan esta palabra clave. 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);
}
Magic Hat
fuente
2
Encontré buenos ejemplos cuando realmente necesitas this en MSDN. Por favor, siga este enlace ... ;-)
Matt
12
Si tiene que comprender y optimizar o reescribir a otra persona, en su mayoría código mal escrito, le thisencantaría tener o cualquier otro calificador para que, desde un simple vistazo, conozca el alcance de la variable (Calificadores de clase omitidos especialmente para constantes (mismo paquete o jerarquía) o super/ basecalificadores). Y usar la sintaxis comúnmente utilizada como _foono parece tan elegante para mí. Presionar _para obtener inteligencia es más lento que ingresar this. ¡Y por qué molestarse en absoluto! Con las funciones de formato de guardado automático de eclipse no es necesario _en caso de que haya olvidado el calificador.
djmj
Después de leer las respuestas y comentarios a continuación, así como de leer la documentación de MSDN: docs.microsoft.com/en-us/previous-versions/visualstudio/… sobre esta palabra clave que no se ha actualizado en 6 años, sugeriría para nunca usar la palabra clave this . Carece de sentido. No haga que los parámetros tengan el mismo nombre, eso es confuso y estúpido. ¿Por qué harías eso? Además, no pase la instancia al usar esto , también es confuso y estúpido.
Yusha

Respuestas:

218

Hay varios usos de esta palabra clave en C #.

  1. Para calificar miembros ocultos por nombre similar
  2. Hacer que un objeto se pase como parámetro a otros métodos
  3. Hacer que un objeto regrese de 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 (estructura) .
  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 alcance, por ejemplo, siguiendo convenciones de nomenclatura comunes y utilizando propiedades (caso Pascal) en lugar de campos (caso camello) para evitar chocar con variables locales (también camello). caso). En C # 3.0, los campos se pueden convertir en propiedades fácilmente mediante el uso de propiedades implementadas automáticamente .

Jakub Šturc
fuente
49
8. Para invocar un método de extensión en la instancia actual ( this.Foo();funcionará, pero Foo()no lo hará)
Marc Gravell
44
También para lanzarse a otro tipo, por ejemplo, un método implementado explícitamente se llamará like ((ICollection<T>)this).Add(bla).
nawfal
44
Para encadenar la construcción a otro constructor definido en el mismo tipo. public ClassName(...) : this(...).
Lasse V. Karlsen
1
@ Y no afectará en absoluto el rendimiento en tiempo de ejecución. Suponiendo que no haya ambigüedad, la salida del compilador es la misma independientemente de si escribe, por ejemplo this.someField = someValueo someField = someValue. Podría afectar el rendimiento del compilador, ya que el compilador analizará el código fuente de manera diferente, pero cualquier diferencia seguramente sería insignificante.
phoog
77
Puede evitar el primer problema accediendo a los campos a través de las propiedades solo si se adhiere a una convención de estilo por la cual las propiedades no pueden tener los mismos nombres que los parámetros. Simplemente sucede que la convención de estilo C # prevaleciente cumple con ese requisito. Sin embargo, no todo C # está escrito bajo esa convención. No hay nada inherente en las propiedades per se que haga thisinnecesaria la palabra clave; un parámetro constructor llamado xocultará un miembro llamado xsi el miembro es un campo, una propiedad o un evento, para el caso.
phoog
246

No quiero decir 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 tendrá éxito si dependerá de si utiliza o no la palabra clave "this" para calificar el acceso a los campos. La palabra clave this no lo ayudará a enviar a tiempo. No va a reducir errores, no tendrá ningún efecto apreciable en la calidad del código o la capacidad de mantenimiento. No le dará un aumento ni le permitirá pasar menos tiempo en la oficina.

Realmente es solo una cuestión de estilo. Si te gusta "esto", úsalo. Si no lo haces, entonces no lo hagas. Si lo necesita para obtener la semántica correcta, úselo. La verdad es que cada programador tiene su propio estilo de programación único. Ese estilo refleja las nociones de ese programador particular de cómo debería ser el "código más estéticamente agradable". Por definición, cualquier otro programador que lea su código tendrá un estilo de programación diferente. Eso significa que siempre habrá algo que hiciste que al otro chico no le gusta o que hubiera hecho de otra manera. En algún momento, un chico 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éticamente agradable posible según sus propios gustos. Si le preguntas a 10 programadores cómo formatear el código, obtendrás unas 15 opiniones diferentes. Una cosa mejor para enfocarse es cómo se factoriza el código. ¿Las cosas se abstraen bien? ¿Elegí nombres significativos para las cosas? ¿Hay mucha duplicación de código? ¿Hay formas de simplificar las cosas? Creo que hacer las cosas bien 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 tipo no examinará cómo inicializa los campos. Él solo va a usar su código, maravillarse de su grandeza,

Scott Wisniewski
fuente
35
La thispalabra clave es semánticamente significativa. Vea el comentario de @ JasonBunting a continuación. Confundes el uso excesivo estilístico de thiscon su propósito real. Tu comentario no es solo impertinente, ¡está mal!
Dan Barowy
12
Si tienes la oportunidad, quizás quieras volver a leer mi respuesta. Hablo de usarlo en los casos en que es necesario para la semántica correcta. También es posible que desee ver la pregunta de origen. Muestra el uso en ejemplos donde no es semánticamente necesario. Por lo tanto, no estoy seguro exactamente de lo que dije que estaba "mal". Mi respuesta ciertamente no es impertinente.
Scott Wisniewski
99
¿Sabes cómo me suena tu respuesta? Entre líneas, leí "¿Cómo te atreves a hacer una pregunta como esta?" - Eso no es realmente constructivo en mi opinión. Nadie lo sabe todo, es por eso que tenemos Stackoverflow: para ayudar a otros y obtener ayuda. Algunos temas que conoces, algunos conocen a otros. Ayúdense unos a otros, no luchen entre ellos. Por favor piénsalo.
Matt
99
No quiero sonar sarcástico, pero esta es una de las peores respuestas hasta ahora. No veo cómo comparar esto con tu trabajo o tu vida personal es útil. El hecho de que algunas cosas sean menos importantes que otras no significa que no sean importantes . Tener un estilo de programación consistente no es importante (lea un libro sobre la legibilidad / mantenibilidad del código de su elección).
aioobe
44
Creo que puede haber entendido mal mi punto. No es que "tener un estilo consistente" sea malo. No digo nada al respecto. Es que la pregunta operativa de "¿debería mi guía de estilo exigir 'esto'? como prefijo para todos los accesos de campo? " Es arbitrario y caprichoso.
Scott Wisniewski
96

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 señala Ryan Fox, cuando necesita pasar esto como un parámetro. (Las variables locales tienen prioridad sobre las variables miembro)

Corey
fuente
66
En este caso, ¿por qué no dar nombres diferentes a las variables de entrada del constructor?
wz366
54

Personalmente, trato de usar esto 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 ven que esto se usa de manera consistente, sabrán si están viendo una variable miembro o no.

Brandon Wood
fuente
99
pero si usted se olvida de usarlo en algún momento, que se confunde
surfen
2
@surfen que puede evitarse mediante comprobaciones de estilo adicionales, por ejemplo, en Java puede usar Checkstyle y ejecutarlo después de una compilación completa (y en cualquier lenguaje iterativo / OO popular habrá herramientas similares)
Maarten Bodewes
55
@surfen como si lo olvidaras en casos ambiguos. Puedo romper cualquier argumento diciendo "pero si te olvidas ...".
Askolein
66
¡La mayoría de las personas parecen nunca leer, optimizar o reescribir el código de otra persona! ¡Los calificadores ahorran tiempo y motivación! Sin calificador es como magia si ves alguna línea de código arbitraria. Así que pierdes todo el tiempo simplemente comprobando de dónde provienen estas variables.
djmj
3
Sé que esta es una publicación muy antigua, pero no puedo evitar comentar la ironía de esta respuesta (con la que estoy de acuerdo). En la Jihad contra la malvada notación húngara, cualquiera que se atreviera a ponerle un prefijo a sus variables miembro con "m_" fue rápidamente ridiculizado porque distinguir las variables miembro simplemente no era útil o necesario.
Michael J.
38

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

Thomas Owens
fuente
Quiero distinguir las variables de clase tanto como pueda, por lo que el código es más claro. Solía ​​usar el prefijo m_ (variable miembro), por ejemplo, cadena privada m_name. Ahora solo uso esto, por ejemplo, si tengo la clase Test {private string a; public someMethod () {this.a = "foo"; }}
banda ancha
36

No puedo creer que todas las personas que dicen que usarlo siempre sea 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 parámetro, como en el ejemplo de Ryan . No hay ninguna razón para usarlo de otra manera porque ser capaz de resolver una variable basada en la cadena de alcance debería ser lo suficientemente claro como para que las variables calificadas con él sean innecesarias.

EDITAR: 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 inconsistencia 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 esos son momentos en los que realmente la necesita . Pegar "esto" frente a las variables en un constructor cuando no hay sombra es simplemente una pérdida de pulsaciones de teclas y una pérdida de mi tiempo al leerlo, no proporciona ningún beneficio.

Jason Bunting
fuente
21
@ JasonBunting : No se puede hacer algo a veces y no algunos otros ... Es confuso ... Yo espero que nunca el trabajo en su código que puede no siempre ASUME que una persona que lee el código en el futuro va a entender lo que escribió, debe ser lo más claro posible, y una forma de lograrlo es ser coherente
juan
@juan, 10 años después. ¿Todavía crees que usar "esto" es una buena práctica? :)
Scott Adams
2
@ScottAdams Sigo creyendo en la coherencia y la claridad, sí
juan
¿Qué pasa con la determinación del alcance de una variable (ya sea local o una variable miembro) con solo mirarla? ¿No está 'esto' justificado para este propósito? ¿O quiere decir que si escribimos métodos más pequeños, de todos modos sería bastante fácil entender el alcance de la variable?
BornToCode
27

Lo uso cuando StyleCop me dice que lo haga . StyleCop debe ser obedecido. Oh si.

Ian Nelson
fuente
1
Y ReSharper me dice que no lo use. Es un poco confuso cuando uso StyleCop y ReSharper al mismo tiempo :) Pero me inclino por la respuesta anterior de Coreys, para usar 'esta' palabra clave solo cuando es absolutamente necesario.
Gunnar
@Gunnar, hay una opción para deshabilitar la eliminación de "esto" redundante. en R #
Winger Sendon
@EmperorAiman: Sí, lo sé. Mi punto era que esas dos herramientas de formato populares son por defecto, lo que sugiere dos cosas diferentes y eso puede ser confuso. "Ser o no ser ..." :)
Gunnar
11

Cada vez que necesite una referencia al objeto actual.

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

Ejemplo:

void onChange()
{
    screen.draw(this);
}
Ryan Fox
fuente
7

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

Philippe
fuente
5

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

El Pitufo
fuente
5

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

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

    object ICloneable.Clone()
    {
        throw new NotImplementedException();
    }
}
Paul Batum
fuente
4

Aquí es cuando lo uso:

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

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

Vaibhav
fuente
4

[C ++]

Estoy de acuerdo con la brigada "úsala cuando tengas que hacerlo". Decorar código innecesariamente con esto no es una gran idea porque el compilador no te avisará cuando olvides hacerlo. Esto introduce una posible confusión para las personas que esperan que esto siempre esté ahí, es decir, tendrán que pensarlo .

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

  • Pasar "usted mismo" a una función.
  • Asignarse "usted mismo" a un puntero o algo así.
  • Fundición, es decir, fundición ascendente / descendente (segura o no), desechando la constidad, etc.
  • Desambiguación forzada del compilador.
Mella
fuente
3

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

juan
fuente
3

Lo uso cuando, en una función que acepta una referencia a un objeto del mismo tipo, quiero dejar perfectamente 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() ;
  }
} ;

De un vistazo, ¿a qué AABB se right()refiere? El thisagrega un poco de clarificador.

bobobobo
fuente
3

En la respuesta de Jakub Šturc, su # 5 sobre el paso de datos entre constructores probablemente podría usar una pequeña explicación. Esto está en sobrecargar a los constructores y es el caso en el que el uso de thises 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.

Cyberherbalist
fuente
2

Tengo la costumbre de usarlo generosamente en Visual C ++, ya que al hacerlo activaría IntelliSense, presioné la tecla '>' y soy flojo. (y propenso a los 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.

JohnMcG
fuente
1

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

JamesSugrue
fuente
1

Prácticamente solo uso esto cuando hago referencia a una propiedad de tipo dentro del mismo tipo. Como otro usuario mencionó, también subrayo los campos locales para que sean notables sin necesidad de esto .

akmad
fuente
1

Lo uso solo cuando es necesario, excepto para operaciones simétricas que, debido al polimorfismo de un solo argumento, deben ponerse en métodos de un lado:

boolean sameValue (SomeNum other) {
   return this.importantValue == other.importantValue;
} 
Pete Kirkham
fuente
1

[C ++]

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

A a;
a = a;

Su operador de asignación se escribirá:

A& A::operator=(const A& a) {
    if (this == &a) return *this;

    // we know both sides of the = operator are different, do something...

    return *this;
}
Apilador
fuente
1

this en un compilador de C ++

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

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

Pero a veces, simplemente no quieres que el compilador adivine. Desea que el compilador 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 variable miembro. Simplemente no quiero que se tome algún símbolo aleatorio solo porque escribí en printflugar de print. this->printfNo habría compilado.

El punto es que, con las bibliotecas heredadas de C (§), el código heredado escrito hace años (§§), o lo que pueda suceder en un lenguaje donde copiar / pegar es una característica obsoleta pero aún activa, a veces, le dice al compilador que no se reproduzca El ingenio es una gran idea.

Estas son las razones que uso this.

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

(§§) 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 en la vida de un programador

paercebal
fuente
1

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

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

Por lo general, lo elimino una vez que tengo lo que estaba buscando: pero este es solo mi estilo que se rompe.

En términos de estilo, si eres un llanero solitario, tú decides; si trabaja para una empresa, cumpla con la política de la empresa (mire las cosas en el control de código fuente y vea lo que otras personas están haciendo). En términos de usarlo para calificar miembros, ninguno es correcto o incorrecto. Lo único incorrecto es la inconsistencia, esa es la regla de oro del estilo. Deja a los pelos de punta otros. Dedique su tiempo a reflexionar sobre problemas de codificación reales, y obviamente codificación, en su lugar.

Jonathan C Dickinson
fuente
1

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 facilidad de mantenimiento.


fuente
1

Cuando hay muchos desarrolladores que trabajan en la misma base de código, necesita algunas pautas / reglas de código. Donde trabajo, hemos decidido 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 al diferenciar entre variables de clase y variables de método.

Paw Baltzersen
fuente
0

Depende del estándar de codificación con el que estoy trabajando. Si estamos usando _ para denotar una variable de instancia, entonces "esto" se vuelve redundante. Si no estamos usando _, entonces tiendo a usar esto para denotar la variable de instancia.

Dan Blair
fuente
0

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

Mark Ransom
fuente
0

1 - Idioma común de Java setter:

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

2 - Al llamar a una función con este objeto como parámetro

notifier.addListener(this);
Delgado
fuente
0

Hay un uso que aún no se ha mencionado en C ++, y que no se refiere al propio objeto o desambigua un miembro de una variable recibida.

Puede usar thispara convertir un nombre no dependiente en un nombre dependiente de argumento dentro de las clases de plantilla que heredan de otras plantillas.

template <typename T>
struct base {
   void f() {}
};

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

Las plantillas se compilan con un mecanismo de dos pasos. Durante el primer paso, solo se resuelven y verifican los nombres dependientes que no son argumentos, mientras que los nombres dependientes se verifican solo por coherencia, sin sustituir realmente los argumentos de plantilla.

En ese paso, sin sustituir realmente el tipo, el compilador casi no tiene información de lo que base<T>podría ser (tenga en cuenta que la especialización de la plantilla base puede convertirla en tipos completamente diferentes, incluso tipos indefinidos), por lo que simplemente asume que es un tipo . En esta etapa, la llamada no dependiente fque parece natural para el programador es un símbolo que el compilador debe encontrar como miembro dederived o en espacios de nombres adjuntos, lo que no ocurre en el ejemplo, y se quejará.

La solución es convertir el nombre no dependiente fen un nombre dependiente. Esto se puede hacer de dos maneras, indicando explícitamente el tipo donde se implementa ( base<T>::fagregando que base<T>hace que el símbolo dependa Ty el compilador asumirá que existirá y pospondrá la verificación real para el segundo pase, después de sustitución de argumentos

La segunda forma, mucho clasificador si hereda 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<T>) this->depende del argumento, y obtenemos el mismo resultado: this->fse verifica en la segunda ronda, después de la sustitución del parámetro de plantilla.

David Rodríguez - dribeas
fuente
-2

No debe usar "esto" a menos que sea absolutamente necesario.

Hay una penalización asociada con verbosidad innecesaria. Debes esforzarte por obtener un código que sea exactamente el tiempo necesario y no más.

dicroce
fuente