ジェネリッククラスでIDisposable
を実装している型を受け取る際は、適切にリソースを破棄する必要がある。
リソースの破棄には以下のようなイディオムが利用できる。
1 2 3 4 5 6 7 8 9 |
public void DoSomething() { var something = new T(); using (something as IDisposable) { something.DoSomething(); } } |
something
がIDisposable
を実装していない場合、キャストの結果はnull
になるので、usingのブロックは実行されない。
ジェネリッククラス自身がIDisposable
を実装しなければならない場合、実装はやや面倒になる。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
public sealed class Something<T> : IDisposable where T : ISomething, new() { private Lazy<T> _something = new Lazy<T>(() => new T()); public void DoSomething() => _something.Value.DoSomething(); public void Dispose() { if (_something.IsValueCreated) { var r = _something.Value as IDisposable; r?.Dispose(); } } } |
ここでは、クラスをsealed
にすることで、Dispose
が必ず実行されるようにしている。
リソースの生成・破棄をクラスの責務から外すことで、実装を簡素化することもできる。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
public sealed class Something<T> where T : ISomething { private readonly T _something; public Something(T something) { _something = something; } public void DoSomething() { _something.DoSomething(); } } |