C#のthisとは?初心者がつまずく使い方・省略できる場面・実例をわかりやすく解説

はじめに

C#を学び始めると、クラスやコンストラクタの中でよく出てくるのがthisです。

たとえば、次のようなコードを見たことがあるかもしれません。

C#
public class User
{
private string name;

public User(string name)
{
this.name = name;
}
}

このthis.name = name;を見て、

thisって何?」
「付けると何が変わるの?」
「省略してもいいの?」
「staticメソッドではなぜ使えないの?」

と疑問に思う初心者は多いです。

C#のthisは、難しそうに見えますが、基本の意味はとてもシンプルです。この記事では、C#のthisについて、初心者がつまずきやすいポイントを中心に、使い方・省略できる場面・実例をわかりやすく解説します。

1. C#のthisとは?初心者向けに意味を一言で解説

1-1. thisは「今操作しているオブジェクト自身」を表すキーワード

C#のthisとは、現在操作しているインスタンス自身を表すキーワードです。

もう少し簡単に言うと、thisは「このオブジェクト」を指します。

たとえば、次のようなクラスがあるとします。

C#
public class Person
{
public string Name;

public void Introduce()
{
Console.WriteLine(this.Name);
}
}

このthis.Nameは、「今このメソッドを実行しているPersonオブジェクトのName」という意味です。

C#
Person person = new Person();
person.Name = "Taro";
person.Introduce();

この場合、Introduceメソッドの中のthisは、personが指しているオブジェクト自身を表します。

つまり、this.Nameperson.Nameのような意味になります。

ただし、クラスの中では変数名personを直接使えるわけではありません。そのため、クラスの内部で「自分自身」を表すためにthisを使います。

1-2. クラス・インスタンス・メンバーの関係からthisを理解する

thisを理解するには、クラス・インスタンス・メンバーの関係を押さえることが大切です。

C#では、クラスはオブジェクトの設計図です。

C#
public class Car
{
public string Color;

public void Drive()
{
Console.WriteLine("走ります");
}
}

このCarクラス自体は、まだ実体ではありません。実際に使うには、newでインスタンスを作ります。

C#
Car car1 = new Car();
Car car2 = new Car();

car1.Color = "Red";
car2.Color = "Blue";

ここでは、同じCarクラスからcar1car2という2つのインスタンスを作っています。

それぞれのインスタンスは、別々のColorを持つことができます。

C#
Console.WriteLine(car1.Color); // Red
Console.WriteLine(car2.Color); // Blue

では、クラスの中でColorにアクセスしたい場合はどうなるでしょうか。

C#
public class Car
{
public string Color;

public void ShowColor()
{
Console.WriteLine(this.Color);
}
}

このthis.Colorは、「このShowColorメソッドを呼び出したインスタンスのColor」を意味します。

C#
car1.ShowColor(); // thisはcar1を指す
car2.ShowColor(); // thisはcar2を指す

同じメソッドでも、どのインスタンスから呼び出されたかによって、thisが指す対象は変わります。

1-3. thisでアクセスできるもの:フィールド・プロパティ・メソッド

thisを使うと、現在のインスタンスが持っているメンバーにアクセスできます。

主にアクセスできるものは、次のようなインスタンスメンバーです。

C#
public class Product
{
private string name;
public int Price { get; set; }

public void ShowInfo()
{
Console.WriteLine($"{this.name}: {this.Price}円");
}

public void SetName(string name)
{
this.name = name;
}
}

このコードでは、thisを使って次のメンバーにアクセスしています。

C#
this.name
this.Price
this.ShowInfo()

this.nameはフィールド、this.Priceはプロパティ、this.ShowInfo()はメソッドを表します。

実際には、メンバー名が重複していなければ、thisを省略できます。

C#
public void ShowInfo()
{
Console.WriteLine($"{name}: {Price}円");
}

このように書いても動きます。

ただし、後ほど解説するように、引数やローカル変数とフィールド名が同じ場合は、thisを使わないと意図したメンバーにアクセスできないことがあります。

1-4. thisが使える場所と使えない場所の全体像

thisは、どこでも使えるわけではありません。

基本的にthisが使えるのは、インスタンスに関係する場所です。

たとえば、次のような場所で使えます。

C#
public class Sample
{
private int value;

public Sample(int value)
{
this.value = value;
}

public void Show()
{
Console.WriteLine(this.value);
}
}

コンストラクタやインスタンスメソッドの中では、thisを使えます。

一方、staticメソッドではthisを使えません。

C#
public class Sample
{
private int value;

public static void Show()
{
// Console.WriteLine(this.value); // エラー
}
}

staticメソッドはインスタンスではなくクラスに属するメソッドなので、「現在のインスタンス」を表すthisが存在しないからです。

また、staticフィールドやstaticプロパティにアクセスするときにも、通常はthisではなくクラス名を使います。

C#
public class Counter
{
public static int Count;

public static void ShowCount()
{
Console.WriteLine(Counter.Count);
}
}

このように、thisは「現在のインスタンス」を表すため、インスタンスが関係しない場所では使えないと覚えておきましょう。

2. thisが必要になる代表例:フィールドと引数の名前が同じとき

2-1. this.name = name; の意味をコードで確認

C#でthisが特によく使われるのは、フィールドと引数の名前が同じときです。

次のコードを見てください。

C#
public class User
{
private string name;

public User(string name)
{
this.name = name;
}
}

ここで出てくるnameは2つあります。

C#
private string name;

これはクラスのフィールドです。

C#
public User(string name)

これはコンストラクタの引数です。

そして、次の行です。

C#
this.name = name;

左側のthis.nameは「このインスタンスのフィールドname」を意味します。

右側のnameは「コンストラクタの引数name」を意味します。

つまり、このコードは次の意味になります。

C#
このオブジェクトのnameフィールドに、引数nameの値を代入する

たとえば、次のようにインスタンスを作ったとします。

C#
User user = new User("Taro");

このとき、コンストラクタの引数nameには"Taro"が入ります。

そして、

C#
this.name = name;

によって、フィールドnameにも"Taro"が代入されます。

2-2. thisを付けないと何を指しているかわからなくなる理由

では、thisを付けずに次のように書くとどうなるでしょうか。

C#
public class User
{
private string name;

public User(string name)
{
name = name;
}
}

一見すると、フィールドに引数を代入しているように見えます。

しかし、このコードでは左側のnameも右側のnameも、コンストラクタの引数nameを指します。

つまり、

C#
name = name;

は「引数nameに引数nameを代入する」という意味になってしまいます。

フィールドのnameには値が入りません。

このように、フィールドと引数の名前が同じ場合、C#ではより近いスコープにある変数、つまり引数のほうが優先されます。

そのため、フィールドを明示したいときはthis.nameと書きます。

C#
this.name = name;

これにより、左側はフィールド、右側は引数だと明確に区別できます。

2-3. コンストラクタでthisを使う基本パターン

コンストラクタでは、引数の値をフィールドやプロパティに代入することがよくあります。

そのため、thisはコンストラクタで特によく登場します。

C#
public class Book
{
private string title;
private int price;

public Book(string title, int price)
{
this.title = title;
this.price = price;
}
}

この書き方は、C#でよく使われる基本パターンです。

プロパティを使う場合も同じです。

C#
public class Book
{
public string Title { get; set; }
public int Price { get; set; }

public Book(string title, int price)
{
this.Title = title;
this.Price = price;
}
}

この場合、Titletitleは大文字・小文字が違うため、thisを省略しても問題ありません。

C#
public Book(string title, int price)
{
Title = title;
Price = price;
}

ただし、this.Titleのように書くと、「インスタンスのプロパティに代入している」という意図が明確になります。

2-4. プロパティやメソッド内でthisを使う例

thisはコンストラクタだけでなく、プロパティやメソッドの中でも使えます。

C#
public class Account
{
private int balance;

public int Balance
{
get
{
return this.balance;
}
}

public void Deposit(int amount)
{
this.balance += amount;
}

public void Withdraw(int amount)
{
this.balance -= amount;
}
}

この例では、balanceフィールドにアクセスするときにthis.balanceと書いています。

メソッドを呼び出すときにもthisを使えます。

C#
public class Account
{
private int balance;

public void Deposit(int amount)
{
this.balance += amount;
this.ShowBalance();
}

public void ShowBalance()
{
Console.WriteLine(this.balance);
}
}

this.ShowBalance()は、現在のインスタンスのShowBalanceメソッドを呼び出すという意味です。

ただし、この場合はthisを省略しても動きます。

C#
ShowBalance();

thisを付けるかどうかは、コードの読みやすさやチームのルールによって判断します。

3. thisを省略できる場面・省略できない場面

3-1. メンバー名が重複していなければthisは省略できる

C#では、多くの場合thisを省略できます。

たとえば、次のコードを見てください。

C#
public class Person
{
private string name;

public void ShowName()
{
Console.WriteLine(name);
}
}

このnameはフィールドです。

同じメソッド内にローカル変数や引数のnameがないため、C#はフィールドのnameだと判断できます。

このコードは、次のように書いても同じ意味です。

C#
public void ShowName()
{
Console.WriteLine(this.name);
}

つまり、メンバー名がほかの変数名と衝突していなければ、thisは省略できます。

プロパティやメソッドでも同じです。

C#
public class Person
{
public string Name { get; set; }

public void Introduce()
{
Console.WriteLine(Name);
}
}

これは次のコードとほぼ同じ意味です。

C#
public void Introduce()
{
Console.WriteLine(this.Name);
}

3-2. ローカル変数や引数とフィールド名が同じならthisで区別する

thisが必要になる代表的な場面は、ローカル変数や引数とフィールド名が同じ場合です。

C#
public class Person
{
private string name;

public void SetName(string name)
{
this.name = name;
}
}

この場合、this.nameはフィールド、nameは引数です。

thisを付けないと、引数のnameが優先されます。

C#
public void SetName(string name)
{
name = name;
}

これではフィールドに値を代入できません。

ローカル変数でも同じです。

C#
public class Sample
{
private int value = 10;

public void Test()
{
int value = 20;

Console.WriteLine(value); // ローカル変数のvalue
Console.WriteLine(this.value); // フィールドのvalue
}
}

このように、同じ名前の変数がある場合、thisを使うことで「インスタンスのメンバー」を明示できます。

3-3. 省略しても動くコードと省略すると意図が伝わりにくいコード

thisは省略できることが多いですが、省略すると意図が伝わりにくくなる場合もあります。

たとえば、次のコードは問題なく動きます。

C#
public class Order
{
private int totalPrice;

public void AddPrice(int price)
{
totalPrice += price;
}
}

このtotalPriceはフィールドだと判断できます。

しかし、コードが長くなったり、ローカル変数が増えたりすると、どれがフィールドでどれが一時的な変数なのか分かりにくくなることがあります。

C#
public class Order
{
private int totalPrice;

public void AddPrice(int price)
{
int tax = 100;
totalPrice += price + tax;
}
}

この程度ならまだ読めますが、複雑な処理では次のように書いたほうが、フィールドへのアクセスだと明確になる場合があります。

C#
public void AddPrice(int price)
{
int tax = 100;
this.totalPrice += price + tax;
}

特に、クラスの状態を変更している処理では、thisを付けることで「このオブジェクトの状態を変えている」と読み取りやすくなります。

3-4. チーム開発でthisを付けるべきか判断する基準

チーム開発では、thisを付けるかどうかはコーディング規約に合わせるのが基本です。

C#では、次のようなスタイルがあります。

C#
this.name = name;
this.age = age;

すべてのインスタンスメンバーにthisを付けるスタイルです。

一方で、次のように必要なときだけthisを付けるスタイルもあります。

C#
name = value;
age = value;

ただし、名前が衝突する場合はthisを付けます。

C#
this.name = name;

どちらが絶対に正しいというわけではありません。

重要なのは、プロジェクト内で書き方を統一することです。

初心者のうちは、次の基準で考えるとよいでしょう。

名前が衝突しているならthisを使う。
フィールドやプロパティへのアクセスを明確にしたいならthisを使う。
コードが冗長に感じるなら省略する。
チームのルールがあるなら、それに従う。

4. thisのよくある使い方を実例で解説

4-1. フィールドに値を代入するときのthis

もっとも基本的なthisの使い方は、フィールドに値を代入する場面です。

C#
public class Student
{
private string name;
private int score;

public Student(string name, int score)
{
this.name = name;
this.score = score;
}
}

このコードでは、コンストラクタの引数をフィールドに代入しています。

C#
this.name = name;
this.score = score;

左側はインスタンスのフィールド、右側は引数です。

プロパティを使う場合も同じです。

C#
public class Student
{
public string Name { get; set; }
public int Score { get; set; }

public Student(string name, int score)
{
this.Name = name;
this.Score = score;
}
}

プロパティ名をName、引数名をnameのように分けておけば、thisを省略しても意味は通じます。

C#
public Student(string name, int score)
{
Name = name;
Score = score;
}

ただし、thisを付けることで、インスタンスのプロパティに代入していることが明確になります。

4-2. インスタンスメソッドを呼び出すときのthis

thisは、同じクラス内のインスタンスメソッドを呼び出すときにも使えます。

C#
public class Logger
{
public void LogInfo(string message)
{
this.Write("INFO", message);
}

private void Write(string level, string message)
{
Console.WriteLine($"[{level}] {message}");
}
}

このthis.Write("INFO", message);は、現在のインスタンスのWriteメソッドを呼び出しています。

ただし、通常は次のようにthisを省略できます。

C#
public void LogInfo(string message)
{
Write("INFO", message);
}

どちらでも動きますが、this.Write()と書くと「同じインスタンスのメソッドを呼んでいる」ということが明確になります。

特に、継承やオーバーライドが関係する場面では、thisが現在のインスタンスを表していることを意識しておくと理解しやすくなります。

4-3. 現在のオブジェクトを別のメソッドに渡すthis

thisは、現在のオブジェクト自身を別のメソッドに渡すときにも使えます。

C#
public class Player
{
public string Name { get; set; }

public void Join(Game game)
{
game.AddPlayer(this);
}
}

public class Game
{
public void AddPlayer(Player player)
{
Console.WriteLine($"{player.Name}が参加しました");
}
}

このコードでは、PlayerクラスのJoinメソッド内で、game.AddPlayer(this);と書いています。

ここでのthisは、現在のPlayerインスタンスを表します。

C#
Player player = new Player();
player.Name = "Taro";

Game game = new Game();
player.Join(game);

この場合、Joinメソッド内のthisplayer自身です。

そのため、

C#
game.AddPlayer(this);

は、現在のプレイヤー自身をゲームに追加するという意味になります。

このように、thisはメンバーにアクセスするだけでなく、オブジェクト自身を引数として渡すときにも使えます。

4-4. メソッドチェーンでreturn thisを使うパターン

thisは、メソッドチェーンを実現するときにも使われます。

メソッドチェーンとは、次のようにメソッドをつなげて呼び出す書き方です。

C#
builder.SetName("Taro")
.SetAge(20)
.Build();

このような書き方を可能にするには、メソッドの戻り値としてthisを返します。

C#
public class UserBuilder
{
private string name;
private int age;

public UserBuilder SetName(string name)
{
this.name = name;
return this;
}

public UserBuilder SetAge(int age)
{
this.age = age;
return this;
}

public User Build()
{
return new User(this.name, this.age);
}
}

return this;は、「現在のUserBuilderインスタンス自身を返す」という意味です。

そのため、次のように続けてメソッドを呼び出せます。

C#
User user = new UserBuilder()
.SetName("Taro")
.SetAge(20)
.Build();

return thisは、ビルダーパターンや設定用のクラスでよく使われます。

初心者のうちは、「自分自身を返すことで、次のメソッド呼び出しにつなげられる」と理解しておくとよいでしょう。

5. コンストラクタで使うthisの2つの意味

5-1. this.メンバーで現在のインスタンスにアクセスする

コンストラクタで使うthisには、大きく分けて2つの意味があります。

1つ目は、これまで見てきたthis.メンバーの形です。

C#
public class Person
{
private string name;
private int age;

public Person(string name, int age)
{
this.name = name;
this.age = age;
}
}

この場合、this.namethis.ageは、現在作成中のインスタンスのフィールドを指します。

コンストラクタは、インスタンスを初期化するための特別なメソッドです。

そのため、コンストラクタの中では、thisを使って「今作っているオブジェクト」に値を設定できます。

C#
Person person = new Person("Taro", 20);

このように書くと、新しく作られるPersonインスタンスに対して、nameageが設定されます。

5-2. this()で同じクラスの別コンストラクタを呼び出す

コンストラクタで使うthisには、もう1つ重要な使い方があります。

それがthis()です。

this()は、同じクラスの別のコンストラクタを呼び出すために使います。

C#
public class Person
{
public string Name { get; set; }
public int Age { get; set; }

public Person() : this("Unknown", 0)
{
}

public Person(string name, int age)
{
this.Name = name;
this.Age = age;
}
}

このコードでは、引数なしのコンストラクタから、引数ありのコンストラクタを呼び出しています。

C#
public Person() : this("Unknown", 0)
{
}

これは、「引数なしでPersonを作った場合は、名前をUnknown、年齢を0として初期化する」という意味です。

C#
Person person = new Person();

この場合、内部的には次のコンストラクタが呼び出されます。

C#
public Person(string name, int age)

このように、this()を使うと、同じクラス内のコンストラクタ処理を再利用できます。

5-3. this()とbase()の違い

this()と似たものに、base()があります。

this()は、同じクラスの別コンストラクタを呼び出します。

一方、base()は、親クラスのコンストラクタを呼び出します。

C#
public class Animal
{
public string Name { get; set; }

public Animal(string name)
{
this.Name = name;
}
}

public class Dog : Animal
{
public Dog(string name) : base(name)
{
}
}

このコードでは、Dogクラスのコンストラクタから、親クラスであるAnimalクラスのコンストラクタを呼び出しています。

C#
public Dog(string name) : base(name)

これは、Animalのコンストラクタにnameを渡して初期化するという意味です。

違いを整理すると、次のようになります。

this()は同じクラスの別コンストラクタを呼ぶ。
base()は親クラスのコンストラクタを呼ぶ。

どちらもコンストラクタの初期化処理を整理するために使いますが、呼び出し先が違います。

5-4. コンストラクタチェーンで重複コードを減らす例

this()を使うと、コンストラクタの重複コードを減らせます。

たとえば、次のようなコードを考えます。

C#
public class Product
{
public string Name { get; set; }
public int Price { get; set; }
public bool IsActive { get; set; }

public Product(string name)
{
this.Name = name;
this.Price = 0;
this.IsActive = true;
}

public Product(string name, int price)
{
this.Name = name;
this.Price = price;
this.IsActive = true;
}
}

このコードでは、NameIsActiveの設定が重複しています。

this()を使うと、次のように整理できます。

C#
public class Product
{
public string Name { get; set; }
public int Price { get; set; }
public bool IsActive { get; set; }

public Product(string name) : this(name, 0)
{
}

public Product(string name, int price)
{
this.Name = name;
this.Price = price;
this.IsActive = true;
}
}

このように、引数の少ないコンストラクタから引数の多いコンストラクタを呼び出すことで、初期化処理を1か所にまとめられます。

これをコンストラクタチェーンと呼びます。

コンストラクタチェーンを使うと、修正箇所が減り、バグも起きにくくなります。

6. staticメソッドでthisが使えない理由

6-1. staticはインスタンスではなくクラスに属する

C#のstaticは、インスタンスではなくクラスに属することを表します。

通常のインスタンスメソッドは、オブジェクトを作ってから呼び出します。

C#
public class Calculator
{
public int Add(int a, int b)
{
return a + b;
}
}

使うときは、次のようにインスタンスを作ります。

C#
Calculator calculator = new Calculator();
int result = calculator.Add(1, 2);

このとき、Addメソッドの中ではthisを使えます。

C#
public int Add(int a, int b)
{
Console.WriteLine(this);
return a + b;
}

一方、staticメソッドはインスタンスを作らずにクラス名から呼び出します。

C#
public class Calculator
{
public static int Add(int a, int b)
{
return a + b;
}
}

使うときは次のようになります。

C#
int result = Calculator.Add(1, 2);

この場合、Calculatorのインスタンスは作られていません。

そのため、thisが指す「現在のインスタンス」が存在しません。

6-2. staticメソッドでthisを使うとエラーになる理由

staticメソッドの中でthisを使うと、コンパイルエラーになります。

C#
public class Sample
{
private int value;

public static void Show()
{
Console.WriteLine(this.value); // エラー
}
}

なぜなら、thisは現在のインスタンスを表すキーワードだからです。

staticメソッドはクラスに属しており、特定のインスタンスに属していません。

そのため、C#は「どのオブジェクトのvalueを表示すればいいのか」を判断できません。

たとえば、次のように複数のインスタンスがあるとします。

C#
Sample s1 = new Sample();
Sample s2 = new Sample();

staticメソッドはs1から呼ばれているわけでも、s2から呼ばれているわけでもありません。

C#
Sample.Show();

そのため、this.valueと書いても、thisが何を指すのか決められないのです。

6-3. インスタンスメソッドとstaticメソッドの違いを比較

インスタンスメソッドとstaticメソッドの違いをコードで比較してみましょう。

C#
public class Counter
{
private int count;

public void Increment()
{
this.count++;
}
}

このIncrementメソッドはインスタンスメソッドです。

インスタンスごとに別々のcountを持てます。

C#
Counter c1 = new Counter();
Counter c2 = new Counter();

c1.Increment();
c2.Increment();

このとき、c1countc2countは別々です。

一方、staticメソッドはクラスに属します。

C#
public class Counter
{
private static int count;

public static void Increment()
{
count++;
}
}

この場合、countstaticにすることで、クラス全体で共有される値になります。

C#
Counter.Increment();
Counter.Increment();

staticメソッドでは、インスタンスごとの状態ではなく、クラス全体に関係する処理を書くのが基本です。

インスタンスメソッドは「特定のオブジェクトの状態を使う処理」。
staticメソッドは「特定のオブジェクトに依存しない処理」。

この違いを理解すると、staticメソッドでthisが使えない理由も自然に理解できます。

6-4. thisが必要な処理をstaticに書いてしまったときの直し方

初心者がよくやってしまうのが、本来インスタンスメソッドに書くべき処理をstaticメソッドに書いてしまうケースです。

C#
public class User
{
private string name;

public static void ShowName()
{
Console.WriteLine(this.name); // エラー
}
}

この処理は、特定のユーザーのnameを表示したい処理です。

つまり、インスタンスの状態を使っています。

そのため、staticを外してインスタンスメソッドにします。

C#
public class User
{
private string name;

public User(string name)
{
this.name = name;
}

public void ShowName()
{
Console.WriteLine(this.name);
}
}

使うときは、インスタンスを作って呼び出します。

C#
User user = new User("Taro");
user.ShowName();

もしstaticメソッドのままにしたい場合は、インスタンスを引数として渡す方法もあります。

C#
public class User
{
public string Name { get; set; }

public static void ShowName(User user)
{
Console.WriteLine(user.Name);
}
}

この場合、thisは使わず、引数userを使ってアクセスします。

C#
User user = new User { Name = "Taro" };
User.ShowName(user);

インスタンスの状態を使うならインスタンスメソッド。
インスタンスに依存しない処理ならstaticメソッド。

この基準で考えると、設計の迷いが減ります。

7. thisを使う特殊な場面:拡張メソッドとインデクサー

7-1. 拡張メソッドの引数に付くthisの意味

C#には、拡張メソッドという機能があります。

拡張メソッドを使うと、既存の型にメソッドを追加したように書けます。

たとえば、stringに独自のメソッドを追加するような書き方ができます。

C#
public static class StringExtensions
{
public static bool IsLong(this string text)
{
return text.Length >= 10;
}
}

このコードのポイントは、引数の前に付いているthisです。

C#
this string text

これは、「このメソッドはstring型に対する拡張メソッドです」という意味です。

使うときは、次のように書けます。

C#
string message = "Hello World";

bool result = message.IsLong();

実際には、IsLongstring型の本物のメソッドではありません。

しかし、拡張メソッドとして定義することで、まるでstringのメソッドのように呼び出せます。

7-2. this int valueのような書き方を初心者向けに解説

拡張メソッドでは、this int valueのような書き方もあります。

C#
public static class IntExtensions
{
public static bool IsEven(this int value)
{
return value % 2 == 0;
}
}

このthis int valueは、「int型の値に対して使える拡張メソッド」という意味です。

使うときは次のようになります。

C#
int number = 10;

bool result = number.IsEven();

number.IsEven()と書くと、内部的にはnumbervalueに渡されます。

イメージとしては、次のような呼び出しに近いです。

C#
bool result = IntExtensions.IsEven(number);

ただし、拡張メソッドとして定義しているため、number.IsEven()のように自然に書けます。

ここで注意したいのは、拡張メソッドのthisは、通常のthis.nameとは少し意味が違うことです。

通常のthisは、現在のインスタンス自身を表します。

一方、拡張メソッドの引数に付くthisは、「どの型を拡張するか」を示すための記法です。

7-3. インデクサーで使うthis[]の意味

C#では、インデクサーを定義するときにもthisを使います。

インデクサーとは、オブジェクトに対して配列のように[]でアクセスできる仕組みです。

C#
public class MyList
{
private string[] items = new string[3];

public string this[int index]
{
get
{
return items[index];
}
set
{
items[index] = value;
}
}
}

この部分がインデクサーです。

C#
public string this[int index]

これは、「このクラスのインスタンスに対して、[index]でアクセスできるようにする」という意味です。

使うときは次のようになります。

C#
MyList list = new MyList();

list[0] = "Apple";
list[1] = "Banana";

Console.WriteLine(list[0]); // Apple

list[0]と書くと、インデクサーのthis[int index]が呼び出されます。

インデクサーのthis[]は、配列やリストのようなアクセス方法を自分のクラスに持たせたいときに使います。

7-4. 通常のthis.メンバーとの違い

ここまでで、thisにはいくつかの使い方があることが分かります。

通常のthis.メンバーは、現在のインスタンスのフィールド・プロパティ・メソッドにアクセスするために使います。

C#
this.name
this.Price
this.Show()

コンストラクタのthis()は、同じクラスの別コンストラクタを呼び出すために使います。

C#
public Person() : this("Unknown")
{
}

拡張メソッドのthisは、どの型を拡張するかを示します。

C#
public static bool IsEven(this int value)

インデクサーのthis[]は、オブジェクトに[]でアクセスできるようにするために使います。

C#
public string this[int index]

同じthisというキーワードでも、書かれている場所によって意味が少し変わります。

初心者のうちは、まずthis.メンバーをしっかり理解しましょう。

その後、this()、拡張メソッド、インデクサーの順に覚えると理解しやすいです。

8. 初心者がつまずきやすいthisのエラーと勘違い

8-1. 「thisは現在のクラス」ではなく「現在のインスタンス」

初心者がよく勘違いするのが、thisを「現在のクラス」と考えてしまうことです。

しかし、正確にはthisは現在のクラスではなく、現在のインスタンスを表します。

たとえば、次のコードを見てください。

C#
public class Person
{
public string Name { get; set; }

public void Show()
{
Console.WriteLine(this.Name);
}
}

このthisPersonクラスそのものではありません。

new Person()で作られた具体的なオブジェクトを指します。

C#
Person p1 = new Person { Name = "Taro" };
Person p2 = new Person { Name = "Hanako" };

p1.Show();
p2.Show();

p1.Show()を呼んだとき、thisp1です。

p2.Show()を呼んだとき、thisp2です。

同じShowメソッドでも、どのインスタンスから呼び出したかによってthisの中身は変わります。

そのため、thisはクラスそのものではなく、実際に作られたインスタンスを指すと覚えましょう。

8-2. thisを付ければ何でもアクセスできるわけではない

thisを付ければ、どんなメンバーにもアクセスできるわけではありません。

thisでアクセスできるのは、基本的に現在のインスタンスから見えるメンバーです。

たとえば、別のクラスのprivateフィールドにはアクセスできません。

C#
public class User
{
private string password;
}

public class UserService
{
public void Show(User user)
{
// Console.WriteLine(user.password); // エラー
}
}

privateメンバーは、そのクラスの内部からしかアクセスできません。

また、thisを使っても、存在しないメンバーにはアクセスできません。

C#
public class User
{
public string Name { get; set; }

public void Show()
{
// Console.WriteLine(this.Age); // Ageがないのでエラー
}
}

thisは魔法のキーワードではありません。

あくまで「現在のインスタンス」を指すだけです。

そのインスタンスが持っていないメンバーや、アクセスできないメンバーにはアクセスできません。

8-3. nullとthisの関係で混乱しやすいポイント

thisnullの関係も、初心者が混乱しやすいポイントです。

通常、インスタンスメソッドの中でthisnullになることはありません。

なぜなら、インスタンスメソッドは基本的にインスタンスに対して呼び出されるからです。

C#
public class User
{
public void Show()
{
Console.WriteLine(this == null);
}
}

通常の呼び出しでは、thisは現在のインスタンスを指します。

C#
User user = new User();
user.Show();

この場合、thisuserです。

ただし、変数自体がnullの場合にインスタンスメソッドを呼び出そうとすると、実行時エラーになります。

C#
User user = null;
user.Show(); // NullReferenceException

この場合、Showメソッドの中でthisnullになるというより、そもそもメソッドを呼び出す対象が存在しないためエラーになります。

つまり、thisは「今動いているインスタンス自身」ですが、インスタンスが存在しない状態ではインスタンスメソッドを呼び出せません。

8-4. 継承時にthisが指すオブジェクトの考え方

継承が関係すると、thisの理解が少し難しく感じることがあります。

次のコードを見てください。

C#
public class Animal
{
public void ShowType()
{
Console.WriteLine(this.GetType().Name);
}
}

public class Dog : Animal
{
}

この場合、Dogインスタンスから親クラスのShowTypeメソッドを呼び出すことができます。

C#
Dog dog = new Dog();
dog.ShowType();

このとき、ShowTypeメソッドはAnimalクラスに定義されています。

しかし、メソッド内のthisAnimalそのものではなく、実際に作られたDogインスタンスを指します。

つまり、継承時でもthisは「今メソッドを呼び出している実際のインスタンス」を表します。

もう少し具体的に見ると、次のようになります。

C#
public class Animal
{
public void Show()
{
Console.WriteLine(this.Name());
}

public virtual string Name()
{
return "Animal";
}
}

public class Dog : Animal
{
public override string Name()
{
return "Dog";
}
}
C#
Animal animal = new Dog();
animal.Show();

この場合、Showメソッド内のthisは、実際にはDogインスタンスです。

そのため、this.Name()ではオーバーライドされたDog側のNameメソッドが呼ばれます。

継承時のthisは、変数の型ではなく、実際のインスタンスを意識すると理解しやすくなります。

9. thisを使うべきか迷ったときの判断基準

9-1. 名前の衝突を避けたいならthisを使う

thisを使うべき代表的な場面は、名前の衝突があるときです。

特に、フィールドと引数の名前が同じ場合は、thisを使うと分かりやすくなります。

C#
public class User
{
private string name;

public User(string name)
{
this.name = name;
}
}

このように書けば、左側のnameがフィールド、右側のnameが引数だとすぐに分かります。

もしthisを書かないと、意図しない動作になることがあります。

C#
public User(string name)
{
name = name;
}

このコードでは、フィールドに値が入りません。

名前が衝突している場合は、迷わずthisを使いましょう。

9-2. コードの意図を明確にしたいならthisを使う

名前が衝突していなくても、コードの意図を明確にしたい場合はthisを使う価値があります。

C#
public class Cart
{
private int total;

public void Add(int price)
{
this.total += price;
}
}

このコードでは、this.totalと書くことで、インスタンスの状態を変更していることが明確になります。

一方、次のように書いても動きます。

C#
public void Add(int price)
{
total += price;
}

短くて読みやすいというメリットはあります。

ただ、クラスの状態を更新していることを強調したい場合は、thisを付けると読み手に伝わりやすくなります。

特に、次のような処理ではthisが役立ちます。

C#
public void CopyFrom(User other)
{
this.Name = other.Name;
this.Age = other.Age;
}

このコードでは、thisがコピー先、otherがコピー元であることが明確です。

9-3. 冗長になるなら省略する

一方で、すべてのメンバーに毎回thisを付けると、コードが冗長に感じることもあります。

C#
public void Show()
{
Console.WriteLine(this.Name);
Console.WriteLine(this.Age);
Console.WriteLine(this.Address);
Console.WriteLine(this.Email);
}

このようにthisが多すぎると、かえって読みづらくなる場合があります。

メンバー名が明確で、名前の衝突もない場合は、省略しても問題ありません。

C#
public void Show()
{
Console.WriteLine(Name);
Console.WriteLine(Age);
Console.WriteLine(Address);
Console.WriteLine(Email);
}

C#では、thisを省略しても意味が分かる場面が多いです。

そのため、必要なときだけthisを付けるスタイルもよく使われます。

ただし、チームやプロジェクトによっては「インスタンスメンバーには必ずthisを付ける」というルールがある場合もあります。

その場合は、プロジェクトの方針に従いましょう。

9-4. 初心者が覚えるべきthisの使い分けチェックリスト

C#のthisを使うべきか迷ったら、次のように考えると整理しやすいです。

フィールドと引数の名前が同じなら、thisを使う。

C#
this.name = name;

現在のインスタンスのメンバーだと明確にしたいなら、thisを使う。

C#
this.total += price;

現在のオブジェクト自身を渡したいなら、thisを使う。

C#
game.AddPlayer(this);

メソッドチェーンを作りたいなら、return thisを使う。

C#
return this;

同じクラスの別コンストラクタを呼びたいなら、this()を使う。

C#
public User() : this("Unknown")
{
}

staticメソッドでは、thisは使えない。

C#
public static void Show()
{
// thisは使えない
}

拡張メソッドでは、第一引数にthisを付ける。

C#
public static bool IsEven(this int value)

インデクサーでは、this[]を使う。

C#
public string this[int index]

初心者のうちは、まず「thisは現在のインスタンス自身」と覚えることが大切です。

そのうえで、名前の衝突を避けるために使う場面から慣れていくと、自然に理解できるようになります。

まとめ

C#のthisは、現在操作しているインスタンス自身を表すキーワードです。

もっともよく使うのは、フィールドと引数の名前が同じときです。

C#
public class User
{
private string name;

public User(string name)
{
this.name = name;
}
}

このthis.name = name;は、「このインスタンスのフィールドnameに、引数nameを代入する」という意味です。

thisは、フィールド・プロパティ・メソッドなど、現在のインスタンスのメンバーにアクセスするときに使えます。

ただし、メンバー名が重複していなければ、多くの場合thisは省略できます。

C#
Console.WriteLine(Name);

一方で、名前の衝突がある場合や、現在のインスタンスを明確にしたい場合は、thisを使うとコードの意図が伝わりやすくなります。

また、コンストラクタではthis.メンバーだけでなく、this()という形で同じクラスの別コンストラクタを呼び出す使い方もあります。

C#
public User() : this("Unknown")
{
}

さらに、拡張メソッドのthis int valueや、インデクサーのthis[int index]のように、少し特殊な使い方もあります。

ただし、最初からすべてを完璧に覚える必要はありません。

まずは、次の3つを押さえましょう。

thisは現在のインスタンス自身を表す。
フィールドと引数の名前が同じときはthisで区別する。
staticメソッドではthisは使えない。

この3つを理解できれば、C#のthisでつまずく場面はかなり減ります。