C#でIDisposableデザインパターンを実装する方法を解説
アンマネージリソース(アンマネージオブジェクト)を確実に解放する必要がある場面では、IDisposableデザインパターン(Disposeパターン)を採用するのが推奨されます。
IDisposableデザインパターンを実装する際は、アンマネージオブジェクトを直接的または間接的に扱うクラスに対してIDisposableインターフェースを実装し、同インターフェース内で宣言されているDisposeメソッドを定義します。実際の開発では、アンマネージオブジェクトを直接操作することはほとんどなく、それらを内部で扱うマネージクラス(ファイルハンドラ、データベース接続文字列、HTTPストリームなど)を経由して利用するのが一般的です。
このパターンの重要なポイントは、オーバーライド可能なDisposeメソッドを提供することで、継承先のクラスでもIDisposableデザインパターンに容易に準拠できるようになる点にあります。さらに、このパターンではファイナライザー(C#ではデストラクタと呼ばれます)の実装も推奨されています。ただし、ファイナライザーはガベージコレクションの動作に影響を与え、パフォーマンス面でのコストが高いため、使用する場合は適切に管理することが重要です。
実装例
static class Program {
static void Main(string[] args) {
using var serviceProxy = new ServiceProxy(null);
serviceProxy.Get();
serviceProxy.Post("");
Console.ReadLine();
}
}
public class ServiceProxy : System.IDisposable {
private readonly HttpClient httpClient;
private bool disposed;
public ServiceProxy(IHttpClientFactory httpClientFactory) {
httpClient = httpClientFactory.CreateClient();
}
~ServiceProxy() {
Dispose(false);
}
public void Dispose() {
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing) {
if (disposed) {
return;
}
if (disposing) {
// マネージオブジェクトの解放
httpClient.Dispose();
}
// アンマネージオブジェクトの解放
disposed = true;
}
public void Get() {
var response = httpClient.GetAsync("");
}
public void Post(string request) {
var response = httpClient.PostAsync("", new StringContent(request));
}
}
コードのポイント
- Dispose(bool disposing):引数disposingがtrueの場合はマネージオブジェクト(HttpClientなど)を解放し、falseの場合はアンマネージリソースのみを対象とします。これにより、明示的な解放とファイナライザーからの呼び出しを正しく区別できます。
- disposedフラグ:既に解放済みの場合は処理をスキップすることで、二重解放を防止し、冪等性を保証します。
- GC.SuppressFinalize(this):Disposeが明示的に呼び出された後はファイナライザーの実行を抑制することで、不要なGCの負荷を軽減します。
- usingステートメント:スコープを抜けた時点で自動的にDisposeが呼び出されるため、リソースの解放漏れを防ぐことができます。
-
C++で学ぶコンポジットパターン(複合デザインパターン)の基礎と実装例
コンポジットパターン(Composite Pattern)は、複数のオブジェクトからなるグループを、あたかも単一のオブジェクトであるかのように扱いたい場面で活用されるデザインパターンです。 このパターンでは、オブジェクトを木構造(ツリー構造)として組み立てることで、「部分」と「全体」の両方の階層を一貫した形で表現できます。オブジェクト群のツリー構造を生成するパターンであるため、GoFデザインパターンの分類では「構造に関するパターン(Structural Patterns)」に属します。 コンポジットパターンの基本概念 コンポジットパターンでは、自分自身と同じ型のオブジェクト群を内部に保持するク
-
Pythonでパターンを出力する方法|三角形・数字・アルファベット・ピラミッドのコード例
Pythonでパターンを出力するには、ネストされた(入れ子構造の)forループを使用します。外側のループで行数を制御し、内側のループで列数を処理します。そしてprint文を工夫することで、目的に応じたさまざまなパターンを作成できます。パターンには、星(アスタリスク)パターン、数字パターン、アルファベットパターンなどがあり、三角形やピラミッドなど、さまざまな形状にも対応できます。パターン出力の基本これらのパターンは、print文を少し変更しながらforループを組み合わせることで出力できます。基本的な考え方はどのパターンも共通しており、違いはごくわずかです。ここからは、代表的なパターンのコードを実