「this」というキーワードはどんなときに使いますか?[閉まっている]

StackOverflow https://stackoverflow.com/questions/23250

  •  09-06-2019
  •  | 
  •  

質問

他の人がどのように使っているのか興味がありました これ キーワード。私はコンストラクターで使用することが多いですが、クラス全体の他のメソッドでも使用する場合があります。いくつかの例:

コンストラクター内:

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

他の場所

public void SomeMethod()
{
    Vector vec = new Vector();
    double d = (vec * vec) - (this.radius * this.radius);
}
役に立ちましたか?

解決

いくつかの使い方がありますが、 これ C#のキーワード。

  1. 類似した名前で隠されているメンバーを認定するには
  2. オブジェクト自体をパラメータとして他のメソッドに渡すには
  3. オブジェクトがメソッドから自身を返すようにするには
  4. インデクサーを宣言するには
  5. 拡張メソッドを宣言するには
  6. コンストラクター間でパラメーターを渡すには
  7. 値の型 (構造体) の値を内部的に再割り当てするには.
  8. 現在のインスタンスで拡張メソッドを呼び出すには
  9. 自分自身を別の型にキャストするには
  10. 同じクラスで定義されたコンストラクターをチェーンするには

最初の使用方法は、スコープ内に同じ名前のメンバー変数とローカル変数を持たないようにすることで回避できます。たとえば、一般的な命名規則に従い、フィールド (キャメル ケース) の代わりにプロパティ (パスカル ケース) を使用してローカル変数 (キャメル ケースも) との衝突を避けることができます。場合)。C# 3.0 では、次を使用してフィールドをプロパティに簡単に変換できます。 自動実装プロパティ.

他のヒント

嫌味に聞こえるつもりはありませんが、それは問題ではありません。

真剣に。

重要なものに注目してください。あなたのプロジェクト、コード、仕事、私生活。フィールドへのアクセスを制限するために "this" キーワードを使用するかどうかによって、成功が左右されるものはありません。このキーワードは予定通りに発送するのには役立ちません。バグは減りませんし、コードの品質や保守性にも目立った影響はありません。これでは昇給も得られませんし、オフィスで過ごす時間を減らすこともできません。

それは本当に単なるスタイルの問題です。「これ」が気に入ったら使ってください。そうしないなら、しないでください。正しいセマンティクスを取得するために必要な場合は、それを使用してください。真実は、すべてのプログラマーが独自のプログラミング スタイルを持っているということです。そのスタイルは、「最も美しいコード」とはどのようなものであるべきかという特定のプログラマーの概念を反映しています。定義上、あなたのコードを読む他のプログラマは、異なるプログラミング スタイルを持つことになります。つまり、あなたがしたことで相手が気に入らなかったり、別のことをしたであろうことが常にあるということです。ある時点で、誰かがあなたのコードを読んで何かについて不平を言うでしょう。

心配することはありません。コードがあなたの好みに合わせてできるだけ美しく見えるようにするだけです。10 人のプログラマーにコードのフォーマット方法を尋ねると、約 15 の異なる意見が得られるでしょう。コードがどのように分解されるかに注目したほうがよいでしょう。物事は正しく抽象化されていますか?私は物事に意味のある名前を付けましたか?コードの重複がたくさんありますか?物事を簡素化する方法はありますか?これらを正しく行うことは、プロジェクト、コード、仕事、人生に最大のプラスの影響を与えると思います。偶然にも、それはおそらく他の男性の不平不満を最も少なくする原因にもなるでしょう。コードが機能し、読みやすく、よく因数分解されていれば、他の人はフィールドの初期化方法を精査することはありません。彼はあなたのコードを使用し、その素晴らしさに驚嘆してから、別のことに移ろうとしているだけです。

私はこれを絶対に必要な場合、つまり、別の変数が別の変数をシャドウしている場合にのみ使用します。ここのように:

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

}

または、Ryan Fox が指摘しているように、これをパラメータとして渡す必要がある場合です。(ローカル変数はメンバー変数より優先されます)

個人的には常に使用するようにしています これ メンバー変数を参照する場合。コードを明確にし、読みやすくするのに役立ちます。たとえ曖昧さがないとしても、私のコードを初めて読む人にはそれが分かりません。 これ 一貫して使用すると、メンバー変数を見ているかどうかがわかります。

必要がない場合でも、インスタンス変数を参照するたびにこれを使用します。コードがより明確になると思います。

これを常に使用することが「ベスト プラクティス」であるなどと言う人が全員信じられません。

次のように、あいまいさがある場合は「this」を使用します。 コーリーの例 または、次のようにオブジェクトをパラメータとして渡す必要がある場合 ライアンの例. 。スコープ チェーンに基づいて変数を解決できることは明らかであり、スコープ チェーンで変数を修飾する必要はないため、それ以外の方法でこれを使用する理由はありません。

編集:「this」に関する C# ドキュメントには、「this」キーワードの使用法が、私が述べた 2 つ以外にもう 1 つ示されています。 インデクサーの宣言用

編集:@ファン:うーん、私のステートメントに矛盾は見当たりません。(C# ドキュメントに記載されているように) "this" キーワードを使用する場合が 3 回あります。これらは実際に 必要 それ。シャドウイングが行われていないときにコンストラクター内の変数の前に「this」を貼り付けることは、単なるキーストロークの無駄であり、それを読むときの時間の無駄であり、何のメリットもありません。

いつでも使ってます スタイルコップ と私に言います。 スタイルコップ 従わなければなりません。そうそう。

現在のオブジェクトへの参照が必要なときはいつでも。

特に便利なシナリオの 1 つは、オブジェクトが関数を呼び出していて、その関数に自分自身を渡したい場合です。

例:

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

私は、扱っているのがインスタンスのメンバーであることを明確にするために、どこでもこれを使用する傾向があります。

あいまいさがある可能性がある場合はどこでも(当然ですが)それを使用します。コンパイラのあいまいさ (その場合は必須) だけでなく、コードを見る人にとってもあいまいさがあります。

this キーワードのもう 1 つのややまれな用途は、実装クラス内から明示的なインターフェイス実装を呼び出す必要がある場合です。以下に不自然な例を示します。

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

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

私が使用するときは次のとおりです。

  • クラス内からプライベート メソッドにアクセスする (区別するため)
  • 現在のオブジェクトを別のメソッドに渡す (または、イベントの場合は送信側オブジェクトとして)
  • 拡張メソッドを作成するとき:D

プライベート フィールド変数名の前にアンダースコア (_) を付けるため、プライベート フィールドにはこれを使用しません。

[C++]

私は「必要な場合に使用する」旅団に同意します。コードを不必要に装飾する これ これは、実行を忘れた場合にコンパイラが警告しないため、良いアイデアではありません。これにより、期待している人々に潜在的な混乱が生じます。 これ 常にそこにいること、つまり彼らはそうしなければならないだろう 考える それについて。

では、いつ使用しますか?ランダムなコードを調べて、これらの例を見つけました(これらが正しいかどうかについては判断していません) 良い やるべきこと、その他):

  • 「自分自身」を関数に渡します。
  • ポインターなどに「自分自身」を代入する。
  • キャスティング、つまりアップ/ダウンキャスト (安全かどうか)、constness のキャストなど。
  • コンパイラによる曖昧さ回避が強制されました。

同じ型のオブジェクトへの参照を受け入れる関数内で、それを作成したいときに使用します。 完全にクリア 私が言及しているオブジェクトはどこですか。

例えば

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

(対)

class AABB
{
  bool intersects( AABB other )
  {
    return other.left() < right() &&
           left() < other.right() &&

           // +y increases going down
           other.top() < bottom() &&
           top() < other.bottom() ;
  }
} ;

AABB が行うことの概要 right() 参照する?の this 少し明確化を加えます。

Jakub Šturc の回答の中で、建設業者間でのデータの受け渡しに関する彼の #5 は、おそらく少し説明できるでしょう。これはコンストラクターのオーバーロードであり、 this 必須です。次の例では、デフォルトのパラメーターを使用して、パラメーターなしのコンストラクターからパラメーター化されたコンストラクターを呼び出すことができます。

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

これは場合によっては特に便利な機能であることがわかりました。

常にこれを使用する必要があります。私はプライベート フィールドとパラメーターを区別するためにこれを使用します (命名規則では、メンバー名とパラメーター名に接頭辞を使用しないと規定されているためです)。また、それらはインターネット上で見つかった情報に基づいているため、ベストプラクティス))

私は、「>」キーを押すと IntelliSense がトリガーされるため、Visual C++ でこれを積極的に使用する習慣がつきました。また、私は怠け者です。(そしてタイプミスが起こりやすい)

しかし、グローバル関数ではなくメンバー関数を呼び出していることがわかると便利なので、私はこれを使い続けています。

私はフィールドに _ を使用して下線を付けることが多いので、実際にはこれを使用する必要はありません。また、R# はとにかくそれらをリファクタリングして取り除く傾向があります...

ほぼこれしか使ってない これ 同じ型内から型プロパティを参照する場合。別のユーザーが述べたように、ローカル フィールドにも下線を付けているので、必要なくても目立つようにしています。 これ.

単一の引数のポリモーフィズムにより片側のメソッドに入れる必要がある対称操作を除いて、必要な場合にのみこれを使用します。

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

[C++]

これ は、代入演算子で使用されます。ほとんどの場合、次のような奇妙な (意図的でない、危険な、またはプログラムの時間の無駄) をチェックして防止する必要があります。

A a;
a = a;

代入演算子は次のように記述されます。

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 C++ コンパイラ上で

C++ コンパイラは、シンボルがすぐに見つからない場合、黙ってシンボルを検索します。場合によっては、ほとんどの場合、それは良いことです。

  • 子クラスでオーバーロードしていない場合は、母クラスのメソッドを使用します。
  • 型の値を別の型にプロモートする

でも時々、 コンパイラに推測させたくないだけです。コンパイラが別のシンボルではなく、正しいシンボルを選択するようにしたいとします。

私にとって, それらは、メソッド内でメンバー メソッドまたはメンバー変数にアクセスしたいときです。私が書いたからといって、ランダムなシンボルがピックアップされるのは望ましくありません printf の代わりに print. this->printf コンパイルされなかったでしょう。

重要なのは、C のレガシー ライブラリ (§)、何年も前に書かれたレガシー コード (§§)、またはその他の言語では、コピー/ペーストが廃止されてもまだ有効な機能である場合、コンパイラーに再生しないように指示することが起こる可能性があるということです。機知は素晴らしいアイデアです。

これらが私が使用する理由です this.

(§) それは私にとってまだ一種の謎ですが、ソースに <windows.h> ヘッダーが含まれているという事実が、すべての従来の C ライブラリ シンボルによってグローバル名前空間が汚染される理由なのではないかと考えています。

(§§) 「ヘッダーをインクルードする必要があるが、このヘッダーをインクルードするとコードが壊れる、というのは一般的な名前を持つ愚かなマクロを使用しているからである」という認識はその 1 つです。 ロシアンルーレット プログラマーの人生の瞬間

'これ。'多くのメンバーを持つ「この」クラスのメンバーを見つけるのに役立ちます(通常、継承チェーンが深いため)。

CTRL+スペースを押しても、型も含まれるため、これには役に立ちません。ここで「これ」メンバーのみが含まれます。

探していたものを手に入れたら、通常は削除します。しかし、これは私のスタイルが突破口を開いただけです。

スタイルに関しては、あなたがローンレンジャーなら、あなたが決めます。会社で働いている場合は、会社のポリシーに従ってください (ソース管理の内容を確認し、他の人が何をしているかを確認してください)。会員の資格を得るためにそれを使用するという点では、どちらが正しいか間違っているかはありません。唯一間違っているのは一貫性がないことです。それがスタイルの黄金律です。他人のうるさいことは放っておいてください。代わりに、実際のコーディングの問題、そして明らかにコーディングの問題について熟考することに時間を費やしてください。

それは、私が作業しているコーディング標準によって異なります。インスタンス変数を示すために _ を使用している場合、「this」は冗長になります。_ を使用していない場合は、インスタンス変数を示すためにこれを使用する傾向があります。

呼び出すために使用します インテリセンス と同じように ジョン・マックG, でも終わったら戻って「this->」を消します。私はメンバー変数の前に「m_」を付けるという Microsoft の規則に従っているので、これをドキュメントとして残すのは冗長になるだけです。

1 - 一般的な Java セッターのイディオム:

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

2 - このオブジェクトをパラメータとして関数を呼び出すとき

notifier.addListener(this);

できるときはいつも使っています。これによりコードがより読みやすくなり、コードがより読みやすくなるということは、バグが減り、保守性が向上することに等しいと私は信じています。

多くの開発者が同じコード ベースで作業している場合、いくつかのコード ガイドライン/ルールが必要になります。私が働いている場所では、フィールド、プロパティ、イベントに「this」を使用することに決めました。

私にとって、このようにすることは理にかなっていて、クラス変数とメソッド変数を区別するときにコードが読みやすくなります。

C++ ではまだ言及されていない使用法が 1 つあります。それは、独自のオブジェクトを参照したり、受け取った変数のメンバーを曖昧さなくしたりするためではありません。

使用できます this 他のテンプレートから継承するテンプレート クラス内で、非依存名を引数依存名に変換します。

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

テンプレートは 2 パス メカニズムでコンパイルされます。最初のパスでは、引数に依存しない名前のみが解決およびチェックされ、依存する名前は実際にテンプレート引数を置き換えることなく、一貫性についてのみチェックされます。

このステップでは、実際に型を置換しない限り、コンパイラーは、型を置き換える情報をほとんど持っていません。 base<T> である可能性があります (基本テンプレートを特殊化すると、完全に異なる型、さらには未定義の型に変わる可能性があることに注意してください)。そのため、それが型であると想定しているだけです。この段階では、非依存呼び出し f プログラマにとってはごく自然なことですが、コンパイラはそのメンバーとして見つけなければならないシンボルです。 derived または、名前空間を囲んでいると -- この例では起こりません -- エラーが発生します。

解決策は非依存名を変更することです f 依存名に変換します。これは、実装されるタイプを明示的に指定することによって、いくつかの方法で行うことができます (base<T>::f --追加 base<T> シンボルを次のものに依存させます T そしてコンパイラーはそれが存在すると仮定し、引数の置換後の 2 番目のパスの実際のチェックを延期します。

2 番目の方法は、複数の引数または長い名前を持つテンプレートから継承する場合に、単に this-> シンボルの前。実装しているテンプレート クラスは引数に依存するため (引数は base<T>) this-> は引数に依存しており、同じ結果が得られます。 this->f テンプレート パラメーターの置換後の 2 番目のラウンドでチェックされます。

どうしても必要な場合を除き、「this」を使用しないでください。

不必要な冗長性にはペナルティが伴います。コードの長さは、必要な長さではなく、正確に長くなるように努めるべきです。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top