Quando usi la parola chiave "this"? [chiuso]


249

Ero curioso di sapere come gli altri usano questa parola chiave. Tendo ad usarlo nei costruttori, ma posso anche usarlo in tutta la classe in altri metodi. Qualche esempio:

In un costruttore:

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

Altrove

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

2
Ho trovato buoni esempi quando hai davvero bisogno this di MSDN. Segui questo link ... ;-)
Matt,

12
Se devi capire e ottimizzare o riscrivere qualcun altro, per lo più codice scritto male, saresti felice di avere thiso qualsiasi altro qualificatore in modo che da un semplice aspetto tu conosca l'ambito della variabile (Qualificatori di classe specialmente omessi per le costanti (stesso pacchetto o gerarchia) o super/ basequalificatori). E usare la sintassi comunemente usata come _foonon mi sembra così elegante. Premere _per intellisense richiede più tempo che entrare this. E perché preoccuparsi affatto! Con eclipse le funzioni di formattazione del salvataggio automatico non sono necessarie _nel caso in cui hai dimenticato il qualificatore.
djmj,

Dopo aver letto le risposte e i commenti di seguito, oltre a leggere la documentazione MSDN: docs.microsoft.com/en-us/previous-versions/visualstudio/… su questa parola chiave che non è stata aggiornata da 6 anni, suggerirei per non usare mai questa parola chiave. È inutile. Non rendere i parametri lo stesso nome, è confuso e stupido. Perché dovresti farlo? Inoltre, non passare l'istanza nell'utilizzo di questo , è anche confuso e stupido.
Yusha,

Risposte:


218

Esistono diversi usi di questa parola chiave in C #.

  1. Per qualificare i membri nascosti con un nome simile
  2. Far passare un oggetto come parametro ad altri metodi
  3. Avere un oggetto restituire se stesso da un metodo
  4. Per dichiarare gli indicizzatori
  5. Per dichiarare i metodi di estensione
  6. Passare parametri tra costruttori
  7. Per riassegnare internamente il tipo di valore (struct) valore .
  8. Per invocare un metodo di estensione sull'istanza corrente
  9. Per lanciarsi su un altro tipo
  10. Incatenare i costruttori definiti nella stessa classe

È possibile evitare il primo utilizzo non avendo variabili membro e locali con lo stesso nome nell'ambito, ad esempio seguendo le convenzioni di denominazione comuni e utilizzando le proprietà (caso Pascal) anziché i campi (caso cammello) per evitare di scontrarsi con variabili locali (anche cammello Astuccio). In C # 3.0 i campi possono essere facilmente convertiti in proprietà utilizzando le proprietà implementate automaticamente .


49
8. Per invocare un metodo di estensione this.Foo();Foo()
sull'istanza

4
Anche per lanciare se stesso su un altro tipo, ad esempio un metodo esplicitamente implementato verrà chiamato come ((ICollection<T>)this).Add(bla).
nawfal,

4
Incatenare la costruzione a un altro costruttore definito nello stesso tipo. public ClassName(...) : this(...).
Lasse V. Karlsen,

1
@Anand non influirà in alcun modo sulle prestazioni in fase di esecuzione. Supponendo che non vi siano ambiguità, l'output del compilatore è lo stesso indipendentemente dal fatto che si scriva, ad esempio this.someField = someValueo someField = someValue. Potrebbe influire sulle prestazioni del compilatore, poiché il compilatore analizzerà il codice sorgente in modo diverso, ma qualsiasi differenza sarebbe sicuramente trascurabile.
phoog

7
È possibile evitare il primo problema accedendo ai campi tramite le proprietà solo se si aderisce a una convenzione di stile in base alla quale le proprietà non possono avere gli stessi nomi dei parametri. Accade semplicemente che la convenzione in stile C # prevalente soddisfi tale requisito. Tuttavia, non tutti i C # sono scritti in base a tale convenzione. Non c'è nulla di inerente alle proprietà di per sé che renderebbe thisinutile la parola chiave; un parametro del costruttore chiamato xnasconderà un membro chiamato xindipendentemente dal fatto che il membro sia un campo, una proprietà o un evento.
phoog,

246

Non intendo che ciò sembri snarky, ma non importa.

Sul serio.

Guarda le cose importanti: il tuo progetto, il tuo codice, il tuo lavoro, la tua vita personale. Nessuno di loro avrà il successo basandosi sull'utilizzo o meno della parola chiave "this" per qualificare l'accesso ai campi. Questa parola chiave non ti aiuterà a spedire in tempo. Non ridurrà i bug, non avrà alcun effetto apprezzabile sulla qualità del codice o sulla manutenibilità. Non ti darà un aumento o ti permetterà di trascorrere meno tempo in ufficio.

È davvero solo un problema di stile. Se ti piace "questo", allora usalo. Se non lo fai, allora non farlo. Se ne hai bisogno per ottenere la semantica corretta, allora usala. La verità è che ogni programmatore ha il suo stile di programmazione unico. Quello stile riflette le nozioni di quel particolare programmatore di come dovrebbe apparire il "codice esteticamente più gradevole". Per definizione, qualsiasi altro programmatore che legge il tuo codice avrà uno stile di programmazione diverso. Ciò significa che ci sarà sempre qualcosa che hai fatto che l'altro ragazzo non gradisce o che avrebbe fatto diversamente. Ad un certo punto un ragazzo leggerà il tuo codice e si lamenterà di qualcosa.

Non mi preoccuperei. Vorrei solo assicurarmi che il codice sia il più esteticamente piacevole possibile secondo i tuoi gusti. Se chiedi a 10 programmatori come formattare il codice, otterrai circa 15 opinioni diverse. Una cosa migliore su cui concentrarsi è come il codice viene preso in considerazione. Le cose sono astratte, giusto? Ho scelto nomi significativi per le cose? C'è molta duplicazione del codice? Ci sono modi in cui posso semplificare le cose? Fare queste cose nel modo giusto, penso, avrà il massimo impatto positivo sul tuo progetto, sul tuo codice, sul tuo lavoro e sulla tua vita. Per coincidenza, probabilmente farà anche brontolare l'altro ragazzo. Se il tuo codice funziona, è facile da leggere ed è ben ponderato, l'altro ragazzo non esaminerà il modo in cui inizializzi i campi. Userà solo il tuo codice, meravigliato della sua grandezza,


35
La thisparola chiave è semanticamente significativa. Vedi il commento di @ JasonBunting qui sotto. Confondi l'abuso stilistico di thiscon il suo scopo reale. La tua osservazione non è solo irriverente, è sbagliata!
Dan Barowy,

12
Se ne hai la possibilità, potresti voler rileggere la mia risposta. Parlo di usarlo nei casi in cui è necessario per la semantica corretta. Potresti anche voler esaminare la domanda sull'origine. Sta mostrando l'uso negli esempi in cui non è semanticamente necessario. Quindi, non sono sicuro esattamente cosa ho detto che fosse "sbagliato". La mia risposta non è certamente irriverente.
Scott Wisniewski il

9
Sai come mi suona la tua risposta? Tra le righe ho letto "Come osi fare una domanda come questa?" - Questo non è davvero costruttivo secondo me. Nessuno sa tutto, ecco perché abbiamo Stackoverflow: aiutare gli altri e ottenere aiuto. Alcuni argomenti che conosci, alcuni conoscono altri. Aiutarsi a vicenda, non combattere gli uni con gli altri. Per favore, pensaci.
Matt

9
Non intendo sembrare snarky, ma questa è una delle peggiori risposte finora. Non vedo quanto sia utile confrontarlo con il tuo lavoro o la tua vita personale. Solo perché alcune cose sono meno importanti di altre non significa che non siano importanti . Avere uno stile di programmazione coerente non è irrilevante (leggi un libro sulla leggibilità del codice / manutenibilità di tua scelta).
Aioobe,

4
Penso che potresti aver frainteso il mio punto. "Non avere uno stile coerente" non è male. Non dico nulla in tal senso. È che la domanda operativa di "dovrebbe la mia guida di stile imporre" questo ". come prefisso per tutti gli accessi ai campi? " è arbitrario e capriccioso.
Scott Wisniewski,

96

Lo uso solo quando assolutamente necessario, cioè quando un'altra variabile ne oscura un'altra. Come qui:

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 come sottolinea Ryan Fox, quando è necessario passare questo come parametro. (Le variabili locali hanno la precedenza sulle variabili dei membri)


6
In questo caso, perché non dare semplicemente nomi diversi alle variabili di input del costruttore?
wz366,

54

Personalmente, cerco di utilizzare sempre questo quando si parla di variabili membro. Aiuta a chiarire il codice e renderlo più leggibile. Anche se non c'è ambiguità, la lettura qualcuno attraverso il mio codice per la prima volta non sa che, ma se vedono questo utilizzato in modo coerente, si saprà se sono alla ricerca in una variabile membro o meno.


9
ma se ti dimentichi di usarlo qualche volta, si confonderanno
navigato il

2
@surfen che può essere evitato da ulteriori controlli di stile, ad esempio in Java puoi usare Checkstyle ed eseguirlo dopo una build completa (e in qualsiasi linguaggio iterativo / OO popolare ci saranno strumenti simili)
Maarten Bodewes

5
@surfen come se lo dimenticassi in casi ambigui. Posso interrompere qualsiasi argomento dicendo "ma se dimentichi ...".
Askolein,

6
La maggior parte delle persone sembra non leggere, ottimizzare o riscrivere mai il codice di qualcun altro! Le qualificazioni fanno risparmiare tempo e motivazione! Senza qualificatore è come una magia se vedi una riga di codice arbitraria. Quindi perdi tutto il tempo solo controllando da dove provengono queste variabili.
djmj,

3
So che questo è un post molto vecchio, ma non posso fare a meno di commentare l'ironia di questa risposta (con la quale mi trovo d'accordo). Nella Jihad contro la malvagia notazione ungherese, chiunque osasse anteporre il prefisso delle proprie variabili membro con "m_" veniva rapidamente messo alla gogna perché distinguere le variabili membro non era utile o necessario.
Michael J.,

38

Lo uso ogni volta che mi riferisco a una variabile di istanza, anche se non ne ho bisogno. Penso che renda il codice più chiaro.


Voglio distinguere il più possibile le variabili di classe, quindi il codice è più chiaro. Ho usato il prefisso m_ (variabile membro) ad es. Stringa privata m_name. Ora lo uso ad es. Se ho classe Test {stringa privata a; public someMethod () {this.a = "foo"; }}
banda larga

36

Non posso credere che tutte le persone che affermano che usarlo sia sempre una "best practice" e cose del genere.

Usa "questo" quando c'è ambiguità, come nell'esempio di Corey o quando devi passare l'oggetto come parametro, come nell'esempio di Ryan . Non vi è alcun motivo per usarlo altrimenti perché essere in grado di risolvere una variabile in base alla catena dell'ambito dovrebbe essere abbastanza chiaro che le variabili qualificanti con esso non dovrebbero essere necessarie.

EDIT: La documentazione C # su "questo" indica un ulteriore uso, oltre ai due che ho citato, per la parola chiave "questo" - per dichiarare gli indicizzatori

EDIT: @Juan: Huh, non vedo alcuna incoerenza nelle mie dichiarazioni - ci sono 3 casi in cui userei la parola chiave "this" (come documentato nella documentazione C #), e quelli sono momenti in cui ne hai davvero bisogno . Attaccare "questo" davanti alle variabili in un costruttore quando non si verificano ombre è semplicemente uno spreco di battiture e una perdita del mio tempo durante la lettura, non offre alcun vantaggio.


21
@ JasonBunting : Non si può fare qualcosa a volte e non alcuni altri ... è confuso ... Mi auguro che non ho mai lavorare in vostro codice è possibile non sempre asume che una persona che legge il codice in futuro sarà capire cosa si ha scritto, devi essere il più chiaro possibile e un modo per raggiungerlo è essere coerente
juan

@juan, 10 anni dopo. Pensi ancora che usare "questo" sia una buona pratica? :)
Scott Adams,

2
@ScottAdams Continuo a credere nella coerenza e nella chiarezza, sì
juan

Che ne dici di determinare l'ambito di una variabile (che sia locale o una variabile membro) semplicemente guardandola? "Questo" non è giustificato per questo scopo? O intendi dire che se scrivessimo metodi più piccoli sarebbe comunque abbastanza facile capire l'ambito della variabile?
BornToCode,

27

Lo uso ogni volta che StyleCop me lo dice. StyleCop deve essere rispettato. Oh si.


1
E ReSharper mi dice di non usarlo. Un po 'di confusione quando uso sia StyleCop che ReSharper allo stesso tempo :) Ma mi appoggio alla risposta di Coreys sopra, per usare la parola chiave "questa" solo quando assolutamente necessario.
Gunnar,

@Gunnar, c'è un'opzione per disabilitare sbarazzarsi di "questo" ridondante. in R #
Winger Sendon,

@EmperorAiman ​​- Sì, lo so. Il mio punto era che questi due popolari strumenti di formattazione sono predefiniti, suggerendo due cose diverse e che possono essere fonte di confusione. "Essere o non essere ..." :)
Gunnar,

11

Ogni volta che hai bisogno di un riferimento all'oggetto corrente.

Uno scenario particolarmente utile è quando il tuo oggetto chiama una funzione e vuole passarci dentro.

Esempio:

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

7

Tendo a usarlo anche ovunque, solo per essere sicuro che siano i membri di istanza di cui ci occupiamo.


5

Lo uso ovunque ci possa essere ambiguità (ovviamente). Non solo ambiguità del compilatore (sarebbe necessaria in quel caso), ma anche ambiguità per qualcuno che guarda il codice.


5

Un altro uso piuttosto raro per questa parola chiave è quando è necessario invocare un'implementazione esplicita dell'interfaccia all'interno della classe di implementazione. Ecco un esempio inventato:

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

    object ICloneable.Clone()
    {
        throw new NotImplementedException();
    }
}

4

Ecco quando lo uso:

  • Accesso ai metodi privati ​​dall'interno della classe (per differenziare)
  • Passare l'oggetto corrente a un altro metodo (o come oggetto mittente, in caso di un evento)
  • Quando si creano metodi di estensione: D

Non lo uso per i campi privati ​​perché antepongo i nomi delle variabili dei campi privati ​​con un trattino basso (_).


4

[C ++]

Concordo con la brigata "usalo quando devi". Decorare il codice inutilmente con questo non è una grande idea perché il compilatore non ti avviserà quando ti dimentichi di farlo. Ciò introduce una potenziale confusione per le persone che si aspettano che ciò sia sempre lì, cioè dovranno pensarci .

Quindi, quando lo useresti? Ho appena dato un'occhiata a qualche codice casuale e ho trovato questi esempi (non sto giudicando se si tratta di cose buone da fare o meno):

  • Passando "te stesso" a una funzione.
  • Assegnare "te stesso" a un puntatore o qualcosa del genere.
  • Casting, ovvero casting up / down (sicuro o meno), casting di costanza, ecc.
  • Disambiguazione forzata del compilatore.

3

Dovresti sempre usarlo, lo uso per differenziare campi e parametri privati ​​(perché le nostre convenzioni di denominazione affermano che non usiamo i prefissi per i nomi dei membri e dei parametri (e sono basati su informazioni trovate su Internet, quindi ritengo che un la migliore pratica))


3

Lo uso quando, in una funzione che accetta un riferimento a un oggetto dello stesso tipo, voglio chiarire perfettamente a quale oggetto mi riferisco, dove.

Per esempio

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 colpo d'occhio a cui fa right()riferimento AABB ? Il thisaggiunge un po 'di un chiarificatore.


3

Nella risposta di Jakub Šturc, il suo n. 5 sul passaggio di dati tra contraenti potrebbe probabilmente usare una piccola spiegazione. Questo è in sovraccarico costruttori ed è l'unico caso in cui l'uso di thisè obbligatorio. Nel seguente esempio possiamo chiamare il costruttore con parametri dal costruttore senza parametri con un parametro predefinito.

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

Ho scoperto che questa è una funzione particolarmente utile in alcune occasioni.


2

Ho preso l'abitudine di usarlo liberamente in Visual C ++ dato che facendo ciò innescerei quelli di IntelliSense che premevo il tasto '>' e sono pigro. (e incline a errori di battitura)

Ma ho continuato a usarlo, poiché trovo utile vedere che sto chiamando una funzione membro piuttosto che una funzione globale.


1

Tendo a sottolineare i campi con _ quindi non ho mai bisogno di usarlo. Anche R # tende a rimuoverli comunque ...


1

Ho praticamente uso solo questo quando si fa riferimento una proprietà di tipo dall'interno dello stesso tipo. Come accennato da un altro utente, sottolineo anche i campi locali in modo che siano evidenti senza bisogno di questo .


1

Lo uso solo quando richiesto, fatta eccezione per le operazioni simmetriche che a causa di polimorfismo a argomento singolo devono essere messe nei metodi di un lato:

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

1

[C ++]

questo viene utilizzato nell'operatore di assegnazione in cui la maggior parte delle volte è necessario controllare e prevenire cose strane (involontarie, pericolose o solo una perdita di tempo per il programma) come:

A a;
a = a;

Il tuo operatore incaricato sarà scritto:

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

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

    return *this;
}

1

this su un compilatore C ++

Il compilatore C ++ cercherà silenziosamente un simbolo se non lo trova immediatamente. A volte, il più delle volte, è buono:

  • usando il metodo della classe madre se non lo hai sovraccaricato nella classe figlio.
  • promuovere un valore di un tipo in un altro tipo

Ma a volte, non vuoi che il compilatore indovini. Volete che il compilatore raccolga il simbolo giusto e non un altro.

Per me , quei tempi sono quando, all'interno di un metodo, voglio accedere a un metodo membro o a una variabile membro. Non voglio che venga preso un simbolo casuale solo perché ho scritto printfinvece di print. this->printfnon avrebbe compilato.

Il punto è che, con le librerie legacy C (§), il codice legacy scritto anni fa (§§) o qualsiasi altra cosa possa accadere in una lingua in cui il copia / incolla è una funzionalità obsoleta ma ancora attiva, a volte, dicendo al compilatore di non giocare L'ingegno è un'ottima idea.

Questi sono i motivi che uso this.

(§) è ancora una specie di mistero per me, ma ora mi chiedo se il fatto che tu includa l'intestazione <windows.h> nella tua fonte, è la ragione per cui tutti i simboli delle librerie C legacy inquineranno il tuo spazio dei nomi globale

(§§) rendersi conto che "è necessario includere un'intestazione, ma includendo questa intestazione si romperà il codice perché utilizza una macro stupida con un nome generico" è uno di quei momenti di roulette russa della vita di un programmatore


1

'Questo.' aiuta a trovare membri in questa "classe" con molti membri (di solito a causa di una catena di eredità profonda).

Colpire CTRL + Spazio non aiuta in questo, perché include anche i tipi; dove-come "questo". include SOLO membri.

Di solito lo cancello una volta che ho quello che stavo cercando: ma questo è solo il mio stile di rottura.

In termini di stile, se sei un ranger solitario - decidi tu; se lavori per un'azienda attenersi alla politica aziendale (guardare le cose nel controllo del codice sorgente e vedere cosa stanno facendo le altre persone). In termini di utilizzo per qualificare i membri, nessuno dei due è giusto o sbagliato. L'unica cosa sbagliata è l'incoerenza: questa è la regola d'oro dello stile. Lasciare gli altri a caccia di nit. Trascorri il tuo tempo a riflettere su problemi di codifica reali - e ovviamente sulla codifica - invece.


1

Lo uso ogni volta che posso. Credo che renda il codice più leggibile e un codice più leggibile equivale a meno bug e più manutenibilità.


1

Quando molti sviluppatori lavorano sulla stessa base di codice, sono necessarie alcune linee guida / regole per il codice. Dove lavoro, abbiamo preferito usare "questo" su campi, proprietà ed eventi.

Per me ha senso farlo in questo modo, facilita la lettura del codice quando si fa una distinzione tra variabili di classe e variabili di metodo.


0

Dipende dallo standard di codifica con cui sto lavorando. Se stiamo usando _ per indicare una variabile di istanza, allora "this" diventa ridondante. Se non stiamo usando _ allora tendo a usarlo per indicare la variabile di istanza.


0

Lo uso per invocare Intellisense proprio come JohnMcG , ma tornerò indietro e cancellerò "this->" quando avrò finito. Seguo la convenzione Microsoft di prefissare le variabili membro con "m_", quindi lasciarla come documentazione sarebbe semplicemente ridondante.


0

1 - Idioma setter Java comune:

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

2 - Quando si chiama una funzione con questo oggetto come parametro

notifier.addListener(this);

0

C'è un uso che non è già stato menzionato in C ++ e che non è fare riferimento al proprio oggetto o disambiguare un membro da una variabile ricevuta.

È possibile utilizzare thisper convertire un nome non dipendente in un nome dipendente dall'argomento all'interno delle classi di modelli che ereditano da altri modelli.

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

I modelli sono compilati con un meccanismo a due passaggi. Durante il primo passaggio, vengono risolti e controllati solo i nomi dipendenti senza argomento, mentre i nomi dipendenti vengono controllati solo per coerenza, senza sostituire effettivamente gli argomenti del modello.

A quel punto, senza sostituire effettivamente il tipo, il compilatore non ha quasi alcuna informazione su ciò che base<T>potrebbe essere (si noti che la specializzazione del modello di base può trasformarlo in tipi completamente diversi, anche tipi non definiti), quindi presuppone solo che sia un tipo . In questa fase la chiamata non dipendente fche sembra naturale al programmatore è un simbolo che il compilatore deve trovare come membro derivedo racchiudendo spazi dei nomi - cosa che non accade nell'esempio - e si lamenterà.

La soluzione sta trasformando il nome non dipendente fin un nome dipendente. Questo può essere fatto in un paio di modi, affermando esplicitamente il tipo in cui è implementato ( base<T>::f--addizionando base<T>il simbolo dipende dal simbolo Te il compilatore supporrà semplicemente che esisterà e rimanderà il controllo effettivo per il secondo passaggio, dopo sostituzione argomento.

Il secondo modo, molto più interessante se erediti da modelli che hanno più di un argomento o nomi lunghi, è semplicemente aggiungere un this->simbolo prima. Poiché la classe modello che stai implementando dipende da un argomento (eredita da base<T>) this->dipende dall'argomento e otteniamo lo stesso risultato: this->fviene verificato nel secondo round, dopo la sostituzione dei parametri del modello.


-2

Non utilizzare "questo" a meno che non sia assolutamente necessario.

C'è una penalità associata a verbosità inutile. Dovresti cercare il codice che è esattamente il tempo necessario e non più.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.