コンストラクタとデストラクタとそのあたり

基本用法

コンストラクタ

インスタンス生成時に自動で実行される
戻り値なし・型名と同名・引数は任意で定義
※構造体については構造体の記事を参照のこと
class Member
{
    public int ID { get; set; }
    public string Name { get; set; }

    // コンストラクタ
    public Member() 
    {
        ID = 0;
        Name = string.Empty;
    }

    // オーバーロード(引数違い)も定義可能
    public Member(int id,string name)
    {
        ID = id;
        Name = name;
    }

    // オーバーロードされたコンストラクタの起動はthisを使用する
    public Member(int id) : this(id,string.Empty)
    {
 
    }
}

親クラスのコンストラクタ

明示的な指定がない場合は、親クラスのデフォルトコンストラクタ(引数無しのコンストラクタ)が起動される
明示的に指定する場合はbaseを使用する
class MemberEx : Member
{
    public string Address{ get; set; }
 
    public MemberEx(int id): base(id)
    {
        Address = string.Empty;
    }
}

静的コンストラクタ

いずれかのクラスメンバへの初回アクセス時に実行される
public static class Member2
{
    public static string Name { get; private set; }
 
    static Member2()
    {
        Name = "Sample";
    }
}

オブジェクト初期化子

インスタンス生成時に公開プロパティ・フィールドを介して初期化を行う
// これまでの方法:コンストラクタ引数や公開プロパティを介す
var mem1 = new Member(1, "AAA");
var mem2 = new Member();
mem2.ID = 2;
mem2.Name = "BBB";
 
// 上記と同等
var mem3 = new Member() { ID = 3, Name = "CCC" };
var mem4 = new Member() { ID = 4, Name = "DDD" };
 
// 括弧()は略記も可能
var mem5 = new Member{ ID = 5, Name = "EEE" };
var mem6 = new Member{ ID = 6, Name = "FFF" };

コレクション初期化子

オブジェクト初期化子のコレクション版

var dict = new Dictionary<int, string>();
dict.Add(1, "AAA");
dict.Add(2, "BBB");

// 上記と同等
var dict2 = new Dictionary<int, string>()
{
    {3,"CCC"},
    {4,"DDD"},
    {5,"EEE"}
};
匿名型 クラス定義を動的に行う
// この場で定義
var shop1 = new { Name = "AAA", Prefecture = "Tokyo" , ID = 3};

// 以下ようにメンバにアクセス可能
var shopName1 = shop1.Name; 

Tuple

組オブジェクトを作成する

// ジェネリックで型定義を行う方法
var shop2 = new Tuple<string, string, int>("BBB", "Osaka", 5);
 
// 静的メソッドを使う方法
var shop3 = Tuple.Create("CCC", "Kyoto", 5);
 
// 以下のように定義順にメンバにアクセス
var shopName2 = shop2.Item1;
var shopName3 = shop3.Item1;

ファイナライザ

以前はデストラクタとも混用されましたがファイナライザで用語が統一されたようです。

・参照型のみ(構造体には定義できない)
・「アクセス指定なし」「~」「型名」「パラメタなし」という形式
class DestructorSample
{
     // ファイナライザ
     ~DestructorSample() 
    {
    }
}
.NET Frameworkの場合
ファイナライザがいつ実行されるかは不定です。ヒープにアロケートされたインスタンスに対し、スタック若しくは静的領域からの参照がない時点においてガーベージコレクタが実行された場合、そのインスタンスはF-Queueと呼ばれる特殊なキューへ繋がれ世代管理されます。この状態で再度ガベージコレクタが実行された場合に対象世代であった場合にファイナライザが定義されていた場合はそれが実行された後にメモリが開放されます。
.NET Core / .NET 5の場合
.NET Core, .NET 5上ではプロセス終了時にファイナライザは実行されません。 理由については以下で述べられています。

API review: During shutdown, revisit finalization and provide a way to clean up resources #16028

代替としてAssemblyLoadContextの使用が勧められています。

IDisposableインタフェース

IDisposableインタフェースはメンバとして引数なし戻型voidのDisposeメソッドが一つ定義されています
これを実現(継承)しているクラスにはusingステートメントが使うこができます。

実装例(.NET Framework用)
class DisposableClass : IDisposable
{
    bool disposed = false;
 
    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);           
    }
 
    protected virtual void Dispose(bool disposing)
    {
        if(!disposed)
        {
            if(disposing)
            {
                // マネージドの解放
            }
            // アンマネージドの解放
            disposed = true;
        }
    }
 
    ~DisposableClass()
    {
        Dispose(false);
    }
}
これを使う方
using (var dst = new DisposableClass())
{
} // このスコープを抜ける時点でdstのDisposeメソッドが呼ばれる