C#: クラスとオブジェクト
1. クラスが必要な理由
C#は、ほぼすべてがオブジェクトであるオブジェクト指向言語です。これまではトップレベル文を使ってコードを書いてきましたが、実際のC#プログラムはクラスから構成されています。クラスはオブジェクトの設計図であり、データ(フィールド)と動作(メソッド)を定義します。一方、オブジェクトはクラスの具体的なインスタンスです。
2. クラスの定義
クラスを定義するには、キーワードclassを使用してください。クラス名はパスカルケース(各単語の頭文字を大文字にする)で記述してください。
class Person
{
public string Name;
public int Age;
public void SayHello()
{
System.Console.WriteLine($"Hello, I'm {Name}, {Age} years old.");
}
}
publicは、そのメンバーが外部からアクセス可能であることを意味しますName、Ageはフィールド(データを格納する)ですSayHelloはメソッド(動作を定義するもの)です
3. オブジェクトの作成
newというキーワードを使用して、クラスからオブジェクトを作成します:
Person p = new Person();
p.Name = "Tom";
p.Age = 18;
p.SayHello();
Hello, I'm Tom, 18 years old.
各newは、独自のフィールドのコピーを持つ独立したオブジェクトを作成します。
4. フィールドとフィールドの初期化
変数には、宣言時に初期値を割り当てることができます:
class Student
{
public string Name = "Unknown";
public int Score = 0;
}
初期値が指定されていない場合、数値型はデフォルトで0となり、参照型はデフォルトでnullとなります。
アクセス修飾子はフィールドの可視性を制御します:
| 修飾語 | 意味 |
|---|---|
public |
どこからでもアクセス可能 |
private |
クラス内でのみアクセス可能(デフォルト) |
通常、フィールドはprivateに設定され、メソッドやプロパティを通じてアクセスが制御されます。
▶ サンプル
using System;
class BankAccount
{
private decimal balance = 1000m;
public void Deposit(decimal amount)
{
balance += amount;
Console.WriteLine($"Deposited {amount}, balance is {balance}");
}
public void ShowBalance()
{
Console.WriteLine($"Current balance: {balance}");
}
}
class Program
{
static void Main()
{
BankAccount acc = new BankAccount();
acc.ShowBalance();
acc.Deposit(500m);
}
}
Current balance: 1000
Deposited 500, balance is 1500
5. 方法
メソッドとは、クラス内で定義され、オブジェクトの挙動を表す関数のことです。メソッドは、同じクラス内のフィールドにアクセスすることができます:
class Calculator
{
private int result = 0;
public void Add(int value)
{
result += value;
}
public int GetResult()
{
return result;
}
}
6. this キーワード
thisは、現在のオブジェクトインスタンスを指します。最も一般的な用途は、同じ名前を持つフィールドとパラメータを区別することです:
class Person
{
public string Name;
public int Age;
public Person(string Name, int Age)
{
this.Name = Name;
this.Age = Age;
}
}
this.Nameはフィールドを指し、Nameはパラメータを指します- 曖昧さが生じない場合は、
thisを省略してもよい
7. コンストラクタ
コンストラクタは、オブジェクトが作成される際に自動的に呼び出され、オブジェクトの初期化に使用されます。
(1) パラメータなしのコンストラクタ
コンストラクタが定義されていない場合、コンパイラは自動的に引数なしのコンストラクタを生成します:
class Dog
{
public string Name;
public Dog()
{
Name = "Unnamed";
}
}
(2) パラメータ付きコンストラクタ
class Dog
{
public string Name;
public Dog(string name)
{
Name = name;
}
}
⚠️ コンストラクタを定義すると、コンパイラはそれ以降、パラメータなしのコンストラクタを自動的に生成しなくなります。
(3) コンストラクタのオーバーロード
異なるパラメータを持つ複数のコンストラクタを定義することができます:
class Dog
{
public string Name;
public int Age;
public Dog()
{
Name = "Unnamed";
Age = 0;
}
public Dog(string name)
{
Name = name;
Age = 0;
}
public Dog(string name, int age)
{
Name = name;
Age = age;
}
}
(4) コンストラクタの連鎖
this(...)を使用すると、あるコンストラクタから別のコンストラクタを呼び出すことができ、コードの重複を回避できます:
class Dog
{
public string Name;
public int Age;
public Dog() : this("Unnamed", 0) { }
public Dog(string name) : this(name, 0) { }
public Dog(string name, int age)
{
Name = name;
Age = age;
}
}
▶ サンプル
using System;
class Book
{
public string Title;
public string Author;
public decimal Price;
public Book() : this("Unknown", "Unknown", 0m) { }
public Book(string title, string author) : this(title, author, 29.9m) { }
public Book(string title, string author, decimal price)
{
Title = title;
Author = author;
Price = price;
}
public void PrintInfo()
{
Console.WriteLine($"\"{Title}\" Author: {Author} Price: {Price}");
}
}
class Program
{
static void Main()
{
Book b1 = new Book();
Book b2 = new Book("C# Basics", "Alice");
Book b3 = new Book("Advanced C#", "Bob", 59.9m);
b1.PrintInfo();
b2.PrintInfo();
b3.PrintInfo();
}
}
"Unknown" Author: Unknown Price: 0
"C# Basics" Author: Alice Price: 29.9
"Advanced C#" Author: Bob Price: 59.9
8. デストラクタ
オブジェクトがガベージコレクションされる前に、デストラクタが呼び出されます。構文は~ClassName()です:
class Resource
{
~Resource()
{
Console.WriteLine("Object is being reclaimed");
}
}
📌 C# には自動ガベージコレクション(GC)が備わっているため、デストラクタを手動で記述する必要はほとんどありません。デストラクタは、アンマネージドリソース(ファイルハンドルやデータベース接続など)を解放するためにのみ使用されます。これについては、後のレッスンで詳しく説明します。
9. オブジェクト初期化子
C# 3.0 では、オブジェクト初期化子の構文が導入されました。これにより、newを使用する際、パブリックフィールドやプロパティに値を直接代入できるようになりました:
Person p = new Person { Name = "Lily", Age = 20 };
これは、次の式と同等です:
Person p = new Person();
p.Name = "Lily";
p.Age = 20;
オブジェクト初期化子は、パラメータ付きコンストラクタと組み合わせることができます:
Person p = new Person("Lily") { Age = 20 };
▶ サンプル
using System;
class Rectangle
{
public double Width = 1;
public double Height = 1;
public double Area()
{
return Width * Height;
}
}
class Program
{
static void Main()
{
Rectangle r1 = new Rectangle();
Rectangle r2 = new Rectangle { Width = 5, Height = 3 };
Rectangle r3 = new Rectangle { Width = 10 };
Console.WriteLine($"r1 area: {r1.Area()}");
Console.WriteLine($"r2 area: {r2.Area()}");
Console.WriteLine($"r3 area: {r3.Area()}");
}
}
r1 area: 1
r2 area: 15
r3 area: 10
10. new と null の違い
| 概念 | 意味 |
|---|---|
new ClassName() |
ヒープ上にオブジェクトを作成し、そのオブジェクトへの参照を返す |
null |
いかなるオブジェクトも指しておらず、参照型のデフォルト値である |
Person p1 = new Person();
Person p2 = null;
Console.WriteLine(p1 == null);
Console.WriteLine(p2 == null);
False
True
⚠️ nullリファレンス上のメンバーにアクセスすると、NullReferenceExceptionが発生します。これはC#で最も一般的な実行時エラーです:
Person p = null;
p.SayHello();
💡 アクセスする前に、nullが含まれているか確認してください:
if (p != null)
{
p.SayHello();
}
❓ よくある質問
📖 まとめ
- クラスとは、オブジェクトの設計図であり、
classで定義されます。 - オブジェクトは
newで作成され、各オブジェクトには独自のフィールドのコピーがあります - フィールドはデータを格納し、メソッドは動作を定義し、
public/privateはアクセスを制御する thisは現在のインスタンスを指し、通常、フィールドと同名のパラメータを区別するために使用されます- コンストラクタはオブジェクトの作成時に自動的に呼び出され、オーバーロードが可能で、チェーン処理には
this(...)を使用できます。 - デストラクタはGCによって自動的に呼び出されるため、通常は手動で記述する必要はありません
- オブジェクト初期化子
new T { Field = value }により、代入が簡略化されます newはオブジェクトを作成し、nullはオブジェクト参照がないことを意味し、nullのメンバにアクセスするとエラーが発生します
📝 練習問題
Carクラスを定義し、その中にBrand(文字列)およびSpeed(整数)のフィールド、Speedの値を増加させるAccelerate(int amount)メソッド、およびSpeedを0に初期化する引数なしのコンストラクタを定義するCarクラスにパラメータ付きコンストラクタCar(string brand)を追加し、this(...)を使用してコンストラクタチェーンを実装する- オブジェクト初期化子を使用して
Carオブジェクトを作成し、BrandとSpeedを設定した後、Accelerateメソッドを呼び出し、最終的なSpeedを出力する - 以下の内容を実装するコードを記述してください:
Carの参照をnullに代入し、そのメンバにアクセスしようとし、try-catch を使ってNullReferenceExceptionを捕捉し、メッセージを出力する