クラス 編集

C#では、クラスはオブジェクト指向プログラミングの基本的な構成要素です。クラスはデータ(フィールドやプロパティ)とそれらのデータを操作するためのメソッド(関数)を含むことができます。以下は、クラスとメソッドの基本的な構造を示すサンプルコードです。

using System;

// クラスの定義
public class MyClass {
  // フィールド(クラス内での変数)
  private string myField;

  // プロパティ(フィールドへのアクセサ)
  public string MyProperty {
    get { return myField; }
    set { myField = value; }
  }

  // コンストラクタ(クラスのインスタンス化時に呼び出されるメソッド)
  public MyClass() {
    // コンストラクタのロジック
    myField = "Default Value";
  }

  // メソッド(クラスの振る舞いを定義する関数)
  public void MyMethod() {
    Console.WriteLine("MyMethod is called!");
  }
}

class Program {
  static void Main(string[] args) {
    // クラスのインスタンス化
    MyClass myObject = new MyClass();

    // プロパティの利用
    myObject.MyProperty = "New Value";
    Console.WriteLine(myObject.MyProperty); // Output: New Value

    // メソッドの呼び出し
    myObject.MyMethod(); // Output: MyMethod is called!
  }
}

このコードでは、MyClassという名前のクラスが定義されています。このクラスはMyPropertyMyMethodというメンバー(プロパティやメソッド)を持っています。Programクラス内のMainメソッドでは、MyClassをインスタンス化し、そのプロパティやメソッドを利用しています。

クラスはプログラム内で再利用でき、オブジェクト指向の特性に基づいてデータと振る舞いを組み合わせて記述することができます。これにより、コードの構造化や保守性の向上が図られます。

フィールドとプロパティ 編集

C#におけるフィールド(field)とプロパティ(property)は、クラス内でデータを保持するための異なる手段です。

フィールド (Field) 編集

フィールドは、クラス内に宣言された変数であり、そのクラスのインスタンスごとに固有のデータを保持します。通常、直接的にアクセスされることがありますが、アクセス修飾子によってアクセス可能な範囲を制限することができます。

public class MyClass {
  private int myField; // フィールドの宣言

  // メソッド内でのフィールドへのアクセス
  public void SetField(int value) {
    myField = value;
  }
}

プロパティ (Property) 編集

プロパティは、フィールドへのアクセスを制御し、フィールドの読み取りや設定に対して特定のロジックを適用するためのメンバーです。プロパティは、外部からフィールドに安全にアクセスするための手段を提供します。通常、プロパティは getset のアクセサーメソッドを持ちます。

public class MyClass {
  private int myField; // フィールド

  // プロパティの定義
  public int MyProperty {
    get { return myField; }  // 値の取得時の処理
    set { myField = value; } // 値の設定時の処理
  }
}
相違点
  1. アクセスの制御: フィールドは直接アクセスされるため、制御が限られますが、プロパティは getset を使用してアクセスし、値の取得や設定に追加のロジックを組み込むことができます。
  2. カプセル化とバリデーション: プロパティを使用することで、フィールドへのアクセスを制限し、外部からのアクセスに対してバリデーションや追加のロジックを適用することができます。これにより、データの整合性を保ちながらアクセスを制御できます。

一般的なプラクティスとして、フィールドはクラス内部でのみ使用され、外部からはプロパティを介してアクセスすることが推奨されます。これにより、カプセル化を実現し、クラスの内部実装をより柔軟に管理できます。

staticなプロパティとメソッド 編集

C#におけるstaticなプロパティとメソッドは、インスタンス化されたオブジェクトではなく、クラス自体に関連付けられるものです。クラスから直接アクセス可能であり、インスタンスを生成せずに使用できます。

Staticプロパティ 編集

using System;

// クラスの定義
public class MyClass {
  // フィールド(クラス内での変数)
  private string myField;

  // プロパティ(フィールドへのアクセサ)
  public string MyProperty {
    get { return myField; }
    set { myField = value; }
  }

  // コンストラクタ(クラスのインスタンス化時に呼び出されるメソッド)
  public MyClass() {
    // コンストラクタのロジック
    myField = "Default Value";
  }

  // メソッド(クラスの振る舞いを定義する関数)
  public void MyMethod() {
    Console.WriteLine("MyMethod is called!");
  }
}

class Program {
  static void Main(string[] args) {
    // クラスのインスタンス化
    MyClass myObject = new MyClass();

    // プロパティの利用
    myObject.MyProperty = "New Value";
    Console.WriteLine(myObject.MyProperty); // Output: New Value

    // メソッドの呼び出し
    myObject.MyMethod(); // Output: MyMethod is called!
  }
}

MyStaticPropertyはクラスMyClassに属し、MyClass.MyStaticPropertyとしてアクセスされます。インスタンス化されたオブジェクトからではなく、クラス自体からアクセスできるため、複数のインスタンスで共有される値を表すのに便利です。

Staticメソッド 編集

public class MyClass {
    public static void MyStaticMethod() {
        Console.WriteLine("This is a static method");
    }
}

MyStaticMethodはインスタンス化されたオブジェクトではなく、クラスMyClass自体に属しています。MyClass.MyStaticMethod()として呼び出されます。staticメソッドはクラスのインスタンスの状態に依存せず、共通の処理を実行するのに適しています。

staticプロパティやメソッドは、インスタンス化されたオブジェクトに固有の値ではなく、クラスレベルの値や振る舞いを表すのに用いられます。

アクセス修飾子 編集

C#における private, protected, public はアクセス修飾子と呼ばれます。これらはメンバー(フィールド、プロパティ、メソッドなど)がどの範囲でアクセス可能かを制御するために使用されます。privateは同じクラス内からのみアクセス可能、protectedはサブクラス内または同じアセンブリ内からアクセス可能、publicはどこからでもアクセス可能を意味します。これらの修飾子はオブジェクト指向プログラミングにおいて、メンバーの可視性とアクセス権を制御するために重要な役割を果たします。

using System;

public class MyClass {
  private int privateField = 10; // 同じクラス内からのみアクセス可能

  protected int protectedField = 20; // サブクラス内または同じアセンブリ内からアクセス可能

  public int publicField = 30; // どこからでもアクセス可能

  private void PrivateMethod() {
    Console.WriteLine("This is a private method");
  }

  protected void ProtectedMethod() {
    Console.WriteLine("This is a protected method");
  }

  public void PublicMethod() {
    Console.WriteLine("This is a public method");
  }
}

public class SubClass: MyClass {
  public void AccessProtected() {
    Console.WriteLine($"Accessing protected field: {protectedField}"); // サブクラスから protected フィールドにアクセス
    ProtectedMethod(); // サブクラスから protected メソッドを呼び出し
  }
}

class Program {
  static void Main() {
    MyClass obj = new MyClass();
    // privateField は同じクラス内からのみアクセス可能
    // obj.privateField にはアクセスできない

    // 各フィールドとメソッドにアクセス
    Console.WriteLine($"Public field: {obj.publicField}");
    obj.PublicMethod();

    SubClass subObj = new SubClass();
    subObj.AccessProtected(); // サブクラスから protected メンバーにアクセス
  }
}

この例では、MyClassprivateprotectedpublic の各フィールドとメソッドを定義し、それぞれのアクセス修飾子がどのように機能するかを示しています。

カプセル化(Encapsulation) 編集

C#におけるクラスとカプセル化は、オブジェクト指向プログラミングの重要な概念です。カプセル化は、データ(フィールド)とそのデータを操作するメソッド(関数)を1つのユニットにまとめることを指します。これにより、データの隠蔽や制御されたアクセスが可能になります。

フィールドとプロパティ 編集

クラス内には、データを格納するためのフィールドと、外部からアクセスを制御するためのプロパティがあります。

public class MyClass {
  // フィールド(カプセル化されたデータ)
  private int myField;

  // プロパティ(フィールドへのアクセスを制御)
  public int MyProperty {
    get { return myField; }
    set { myField = value; }
  }
}

カプセル化の利点 編集

  1. アクセス制御: フィールドがprivateなので、直接アクセスを制限し、プロパティを通じて間接的にアクセスすることで、データの整合性を保つことができます。
  2. データの隠蔽: 外部から直接的にデータにアクセスできないため、内部の実装の変更があっても外部のコードに影響を与えにくくなります。
  3. バリデーションと制御: プロパティのセッターでデータのバリデーションや追加のロジックを実行することができます。
public class MyClass {
  private int myField;

  public int MyProperty {
    get { return myField; }
    set {
      if (value > 0)
        myField = value;
      else
        throw new ArgumentException("Value must be positive");
    }
  }
}

カプセル化は、クラスのデータを隠蔽し、正しい方法でのみアクセスできるようにすることで、コードの安全性や保守性を向上させます。これにより、コードの予期しない変更や誤った利用を防ぎ、より信頼性の高いプログラムを作成することができます。

継承(Inheritance) 編集

C#における継承(Inheritance)は、既存のクラス(親クラスまたは基底クラスと呼ばれる)の特性や機能を新しいクラス(子クラスまたは派生クラスと呼ばれる)に引き継ぐ仕組みです。これにより、コードの再利用性や階層構造の構築が可能になります。

継承の宣言
// 親クラス
public class Animal {
  public void Eat() {
    Console.WriteLine("Eating...");
  }
}

// 子クラス
public class Dog: Animal {
  public void Bark() {
    Console.WriteLine("Woof!");
  }
}
特性
  1. 基底クラスからのメンバーの引き継ぎ: 子クラスは、基底クラスのフィールド、プロパティ、メソッドを引き継ぐことができます。上記の例では、Dog クラスは Animal クラスの Eat メソッドを持っています。
  2. 新しいメンバーの追加: 子クラスは、独自のフィールド、プロパティ、メソッドを追加できます。Dog クラスには Bark メソッドが追加されています。

オーバーライド(Override) 編集

子クラスで親クラスのメソッドを再定義することをオーバーライドと呼びます。これにより、子クラスは親クラスのメソッドをカスタマイズすることができます。

// 親クラス
public class Animal {
  public virtual void MakeSound() {
    Console.WriteLine("Some sound");
  }
}

// 子クラス
public class Dog: Animal {
  public override void MakeSound() {
    Console.WriteLine("Woof!");
  }
}
注意点
  • C#では単一継承のみサポートされます。つまり、1つのクラスは1つの親クラスしか持つことができません。
  • sealed キーワードを使用することで、特定のクラスを継承不可にすることも可能です。

継承は、コードの再利用性や階層構造の明確化に役立ちますが、過度な継承の使用はコードの理解や保守性を複雑にする可能性があります。したがって、適切に設計された継承構造を持つことが重要です。

sealedクラスとsealedメソッド 編集

C#における sealed キーワードは、クラスやメソッドに対して使用され、それらを継承やオーバーライドから封印(sealed)するためのものです。

sealed クラス 編集

sealed クラスは、継承を禁止するために使用されます。つまり、sealed キーワードが付いたクラスは継承できません。

public sealed class SealedClass {
  // クラスの内容
}

上記のように sealed クラスを宣言すると、これを継承することはできません。例えば、この SealedClass を継承しようとする場合、コンパイルエラーが発生します。

sealed メソッド 編集

sealed メソッドは、基底クラスで宣言されたメソッドを派生クラスでオーバーライドできないようにします。

public class BaseClass {
  public virtual void OverridableMethod() {
    // 仮想メソッドの内容
  }

  public sealed void SealedMethod() {
    // 封印されたメソッドの内容
  }
}

public class DerivedClass: BaseClass {
  // 以下はエラーとなります
  // public override void SealedMethod() { ... }
}

上記の例では、BaseClassSealedMethodsealed 修飾しています。このため、DerivedClassSealedMethod をオーバーライドすることはできず、コンパイルエラーが発生します。

sealed キーワードは、特定のクラスやメソッドを拡張不可にしたり、オーバーライド不可にするために使われます。これにより、意図せぬ変更や拡張が行われることを防ぐことができます。

なぜ sealed が必要か?
クラス
  1. セキュリティと信頼性: sealed クラスは、セキュリティ上の理由や信頼性を保証するために使われることがあります。特定のクラスの実装が完了しており、それを変更させたくない場合や、クラスが意図した方法で使用されることを保証するために sealed を使用します。
  2. パフォーマンスの最適化: 一部のケースでは、sealed クラスを使用することで、コンパイラーが最適化を行う機会を提供します。派生クラスが存在しないことがわかっている場合、コンパイラーは最適化を行い、メソッドの呼び出しをより効率的に処理することができます。
メソッド
  1. オーバーライドの抑制: 基底クラスで sealed を使用してメソッドを封印することで、派生クラスがそのメソッドをオーバーライドできないようにします。これは、派生クラスによる誤った実装やメソッドの意図しない変更を防ぐのに役立ちます。
  2. APIの安定性と互換性の維持: sealed メソッドは、クラスのAPIの安定性と互換性を維持するために使用されます。特定のメソッドが派生クラスでオーバーライドされることを防ぎ、将来的なバージョンでの互換性を保つのに役立ちます。

sealed キーワードは、クラスやメソッドの意図しない変更や拡張を防ぐために、プログラムの安定性や信頼性を向上させるための手段として使用されます。そのため、安定性やセキュリティを確保するために有用な機能と言えます。

多重継承不可 編集

C#では、クラスにおける多重継承(複数のクラスからの継承)はサポートされていません。言い換えると、C#においては1つのクラスは複数の親クラスからの特性や機能を直接的に継承することができません。

この制限は、複数の親クラスからの継承によって生じる潜在的な問題や複雑さを回避するためにあります。多重継承を許可すると、ダイヤモンド継承問題(Diamond Inheritance Problem)などの問題が発生する可能性があります。この問題は、複数の親クラスが同じ祖先クラスを持つ場合、それによって派生クラス内に衝突や競合が生じる可能性があることを指します。

代わりに、C#ではインターフェースを使用して、複数の振る舞いや契約を定義することができます。これにより、1つのクラスが複数のインターフェースを実装することが可能になります。

例えば、次のようにインターフェースを使用できます:

public interface IWalkable {
  void Walk();
}

public interface IFlyable {
  void Fly();
}

public class Bird: IWalkable, IFlyable {
  public void Walk() {
    Console.WriteLine("Bird is walking");
  }

  public void Fly() {
    Console.WriteLine("Bird is flying");
  }
}

このように、複数のインターフェースを実装することで、1つのクラスが異なる振る舞いを持つことができますが、直接的な複数のクラスからの継承は許可されていません。

ポリモーフィズム(Polymorphism) 編集

C#におけるポリモーフィズムは、同じ名前のメソッドや操作子が異なるクラスで異なる振る舞いを示す機能です。これにより、異なるクラスのオブジェクトが同じメソッド名を使用し、それぞれ独自の実装を持つことができます。

ポリモーフィズムの例
public class Animal {
  public virtual void MakeSound() {
    Console.WriteLine("Some sound");
  }
}

public class Dog: Animal {
  public override void MakeSound() {
    Console.WriteLine("Woof!");
  }
}

public class Cat: Animal {
  public override void MakeSound() {
    Console.WriteLine("Meow!");
  }
}

この例では、Animal クラスを継承して Dog クラスと Cat クラスが作成されています。それぞれのサブクラスで MakeSound メソッドをオーバーライドして、犬と猫それぞれの鳴き声を出力しています。

ポリモーフィックな使用例
Animal myAnimal = new Animal();
Animal myDog = new Dog();
Animal myCat = new Cat();

myAnimal.MakeSound(); // "Some sound"
myDog.MakeSound(); // "Woof!"
myCat.MakeSound(); // "Meow!"

これらのオブジェクトはすべて Animal クラスのインスタンスですが、MakeSound メソッドが各オブジェクトの実際の型に基づいて実行されるため、それぞれ異なる結果が得られます。これがポリモーフィズムの特性です。

ポリモーフィズムにより、同じ名前のメソッドを使用してコードをより柔軟に、拡張可能にすることができます。また、実行時にオブジェクトの実際の型に基づいて適切な実装を選択するため、より効率的なコードを書くことができます。

同じ親クラスから派生したクラスのインスタンスを持つ配列とそのイテレーション 編集

同じ親クラスから派生したクラスのインスタンスを持つ配列を作成し、その配列をイテレーションする方法はいくつかあります。以下にいくつかの方法を示します。

using System;

public class Animal {
  public virtual void MakeSound() {
    Console.WriteLine("Some sound");
  }
}

public class Dog: Animal {
  public override void MakeSound() {
    Console.WriteLine("Woof!");
  }
}

public class Cat: Animal {
  public override void MakeSound() {
    Console.WriteLine("Meow!");
  }
}

public class Program {
  public static void Main() {
    Animal[] animals = new Animal[3];
    animals[0] = new Animal(); // 親クラスのインスタンス
    animals[1] = new Dog(); // Dogクラスのインスタンス
    animals[2] = new Cat(); // Catクラスのインスタンス

    // 配列のイテレーション
    foreach(Animal animal in animals) {
      animal.MakeSound(); // 各要素のMakeSoundメソッドを呼び出す
    }
  }
}

このコードは、Animal クラスを親クラスとし、それを継承した Dog クラスと Cat クラスを持つ簡単なポリモーフィズムの例です。

  1. Animal クラスは MakeSound() メソッドを持ち、デフォルトの実装では "Some sound" を出力します。
  2. Dog クラスは Animal クラスを継承し、MakeSound() メソッドをオーバーライドして "Woof!" を出力するようになります。
  3. Cat クラスも同様に Animal クラスを継承し、MakeSound() メソッドをオーバーライドして "Meow!" を出力するようになります。

Main() メソッドでは、Animal クラスの配列 animals を作成し、それぞれの要素に Animal クラスのインスタンス、Dog クラスのインスタンス、Cat クラスのインスタンスを代入しています。その後、foreach ループを使用して配列内の各要素をイテレーションし、それぞれの MakeSound() メソッドを呼び出しています。

結果として、Dog クラスと Cat クラスはそれぞれの MakeSound() メソッドのオーバーライドによって異なる音声を出力し、ポリモーフィズムが実現されています。これにより、同じインターフェースを持つ異なる種類のオブジェクトを同じ方法で処理することができます。

抽象クラスと純粋仮想関数(抽象メソッド) 編集

C#には抽象クラスと純粋仮想関数(抽象メソッド)があります。

抽象クラス(Abstract Class) 編集

抽象クラスは、インスタンス化できないクラスであり、少なくとも1つ以上の抽象メソッドを含むことができます。抽象メソッドは、実装を持たずにメソッドのシグネチャ(戻り値の型とパラメータ)を定義するメソッドです。派生クラスは、抽象クラスから継承し、その抽象メソッドをオーバーライドすることが必要です。

public abstract class AbstractClass {
  public abstract void AbstractMethod(); // 抽象メソッド
  public void RegularMethod() {
    Console.WriteLine("This is a regular method.");
  }
}

public class ConcreteClass: AbstractClass {
  public override void AbstractMethod() {
    Console.WriteLine("Implementation of abstract method.");
  }
}


抽象メソッド(純粋仮想関数) 編集

抽象メソッドは、抽象クラスや抽象メソッドが存在する場合に使用されるもので、メソッドの実装がなく、派生クラスで必ずオーバーライドされるべきメソッドです。抽象メソッドは abstract キーワードを使用して定義されます。

public abstract class AbstractClass {
  public abstract void AbstractMethod(); // 抽象メソッド
}

派生クラスでは、抽象メソッドをオーバーライドして実装する必要があります。

public class ConcreteClass: AbstractClass {
  public override void AbstractMethod() {
    Console.WriteLine("Implementation of abstract method.");
  }
}

抽象クラスや抽象メソッドは、ポリモーフィズムや特定のメソッドの実装を強制するために使用され、実際の実装は派生クラスに委ねられます。これにより、クラス階層の設計やメソッドの一貫性を維持するのに役立ちます。


JavaのクラスとC#のクラスの比較
JavaとC#はどちらもオブジェクト指向プログラミング言語であり、それぞれ独自の特徴を持ったクラスを定義できますが、いくつかの類似点と相違点があります。
類似点
  1. 構文と基本概念: JavaとC#は両方ともクラスベースのオブジェクト指向プログラミング言語であり、クラス、メソッド、フィールド、プロパティなどの基本概念は非常に似ています。
  2. ガベージコレクション: 両言語ともに、ガベージコレクション(自動メモリ管理)を提供しており、メモリ管理が容易です。
  3. カプセル化: 両言語ともに、カプセル化をサポートしており、アクセス修飾子を使ってフィールドやメソッドのアクセス範囲を制御することができます。
相違点
  1. プラットフォーム: Javaはプラットフォームに依存しない言語であり、Java仮想マシン(JVM)上で実行されます。一方、C#はMicrosoftの.NETフレームワーク上で動作し、主にWindows環境で使用されます。
  2. プロパティの構文: C#はプロパティの表現が簡潔であり、getset を使用した自動実装プロパティをサポートしています。Javaには同様の構文はありませんが、JavaBeansなどの慣習により、ゲッターやセッターメソッドを使用してプロパティにアクセスします。
  3. デリゲートとイベント: C#にはデリゲートとイベントという概念がありますが、Javaには直接対応するものはありません。Javaでは、似たような機能をインターフェースやコールバックメソッドを使って実現します。
  4. 例外処理: Javaでは例外処理が非常に重要な役割を果たしていますが、C#では try-catch-finally ブロックに加えて、例外フィルタリングや using ステートメントを使ったリソースの解放など、より多くの機能が提供されています。

これらの違いや類似点は、開発者がプログラムを構築する際に異なるアプローチを取ることに影響します。ただし、両言語は同じオブジェクト指向の原則に基づいており、多くのコンセプトやパターンが共通しています。


C Sharp|くらすとめそつと