TableAdapterって便利ですよね。でも大きな欠点が1つあります。それは内部で保持しているIDisposableを実装しているリソースのDisposeを呼び出さないことです。
そこで、その欠点に対処するヘルパーメソッドを書いてみました。
using System.Data.Common; using System.Reflection; using SystemExtensions; namespace Models { /// <summary> /// <c>TableAdapter</c> をサポートする静的なメソッドを提供します。 /// </summary> public static class TableAdapterHelper { /// <summary> /// 使用しているマネージ リソースを解放します。 /// </summary> /// <param name="tableAdapter">マネージ リソースを解放する<c>TableAdapter</c>。</param> /// <param name="disposing">マネージ リソース解放する場合は true。</param> /// <remarks> /// <c>TableAdapter</c> が保持している <see cref="System.IDisposable"/> 実装リソースの /// <see cref="System.IDisposable.Dispose"/> を呼び出さない不具合に対処します。 /// </remarks> public static void Dispose(Component tableAdapter, bool disposing) { if(disposing) { Type t = tableAdapter.GetType(); DbCommand[] commands = GetField(t, "_commandCollection").GetValue(tableAdapter) as DbCommand[]; if(commands != null) { foreach(DbCommand c in commands) { c.NullSafeDispose(); } } FieldInfo f = GetField(t, "_adapter"); if(f != null) { DbDataAdapter adapter = f.GetValue(tableAdapter) as DbDataAdapter; if(adapter != null) { adapter.UpdateCommand.NullSafeDispose(); adapter.InsertCommand.NullSafeDispose(); adapter.DeleteCommand.NullSafeDispose(); adapter.SelectCommand.NullSafeDispose(); adapter.NullSafeDispose(); } } } } private static FieldInfo GetField(Type type, string fieldName) { FieldInfo fi = type.GetField( fieldName, BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly); return fi; } } }
NullsafeDisposeについてはこちらを参照してください。
拡張メソッドでNullセーフなメソッドを実装する - プログラマーな日々
オブジェクトのNullチェックって面倒ですよね。.Net 3.0以降なら拡張メソッドでNullセーフなメソッドを実装できます。 例えば、IDisposableにNullチェックを入れたDisposeを実装するならこんな感じです。 ...
こんな風に使用します。
using Models; public partial class TableAdapter { /// <summary> /// 使用しているアンマネージ リソースを解放し、オプションでマネージ リソースも解放します。 /// </summary> /// <param name="disposing"> /// マネージ リソースとアンマネージ リソースの両方を解放する場合は true。 /// アンマネージ リソースだけを解放する場合は false。 /// </param> protected override void Dispose(bool disposing) { TableAdapterHelper.Dispose(this, disposing); base.Dispose(disposing); } }
それにしてもなぜMSの開発チームはTableAdapterをSystem.ComponentModel.Componentから直接派生させてしまったのでしょう?せめてTableAdapterBaseとかいうクラスを経由させてくれてたら、リフレクションなんて面倒なことをしなくてもすんだのに。