気楽なソフト工房

プログラミングについていろいろな記事を書いています。



Author:mykonos2008
システムエンジニアとして働いている30代の会社員です。
仕事や趣味でプログラムを書いている方の役に立つ記事を書いていきたいと思っています。
ご意見、ご感想はこちらまで
If you are an english speaker,Please visit my english blog.

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。
さて、いよいよ、「Silverlight4」のリリースが近づいてきましたね、楽しみです。
そこで、本日は「Silverlight4」のComオートメーションのちょっとしたTipsをご紹介させていただきます。

Comオートメーションをアプリから利用する際(Silverlightに限らず)、一番頭を悩ませるのは
一度取得したComオブジェクトのリソース解放です。使用したComオブジェクトを1つでも、
解放し忘れると、Comオブジェクトのプロセスが残ってしまいます。

「Silverlight4」ではComオブジェクトは、「IDisposable」インターフェースを実装しているので、
「using句」を利用したり、直接Dispose()をコールすることで、リソースを解放することが出来ます。

ただ、問題はほとんどの場合、解放しなければいけないオブジェクトが1つで済まないことです。
例えばExcelをComオートメーションで利用して、新規のブックに、データを書き込んで保存処理を
行うとします。
この場合、以下のようなオブジェクトが必要になります。

・Application(Excel)
・Workbooks
・Workbook
・Worksheets
・Worhsheet
・Range
・Font
・Interior

Rangeなんかは入れ子になったりするので、実際はもっと多いです。
これらを「using」句を使って解放するとなると、、、

   using(dynamic excel = AutomationFactory.CreateObject("Excel.Application")){
      using(dynamic workbooks = excel.WorkBooks){
         using(dynamic workbookObject = workbooks.Add()){
            /////////どんどん入れ子に。。。
         }
      }
   }

ちょっときつい。。ですね。。

そこでちょっとしたライブラリを考えてみました。
アプリケーションで、利用するComオブジェクトをラップするクラスを作り、
IDisposableインターフェースを実装します。

例えばWorkbooksのラッパーはこんな感じです。
    public class Workbooks : IDisposable
    {
        //Comオブジェクト
        private dynamic _workbooks;

        internal Workbooks(dynamic workbooks)
        {
            _workbooks = workbooks;
        }

///省略
    }

そして、新規ブック追加など新たなComオブジェクトへの参照が生成される処理で、
以下のようにして、新規生成されたオブジェクトを管理コレクションに登録しておきます。

        public Workbook CreateNewBook()
        {
            dynamic workbookObject = _workbooks.Add();

            //ブックのラッパー
            Workbook workbook = new Workbook(workbookObject);

            //管理コレクションに登録する処理
            AddChildren(workbook);

            return workbook;
        }

そして、Dispose()メソッドの中で、ラップしているComオブジェクトと、管理コレクションに登録されている
派生オブジェクトを解放する処理を記述します。

        public void Dispose()
        {
            try
            {
                //子オブジェクトを解放する
                ReleaseChildren();

                ((IDisposable)_workbooks).Dispose();

            }
            catch { }
        }

こうすることで何がよいかと言うと利用する側は以下のようなコードで済みます。

    using(Workbooks books = excel.Workbooks){
        //いろんな処理
    }

外側のWorkbooksがそれから派生する他のComオブジェクトを管理し、またそれらのラッパークラスが
さらにその子供を管理し、それぞれリソース解放を担ってくれるので、利用する側は、自分が解放したい単位で、
外側のオブジェクト(今回はWorkbooks)を決定し、それのみ解放処理を記述すればよいのです。

実際は、「SilverOffice」という名前のもう少し手の込んだサンプルライブラリを作成してみました。
ただ、オブジェクトやプロパティは全然そろえていないので、考え方が使えそうであれば、
必要なオブジェクトやプロパティを追加して使用してみてください。

SilverOfficeのダウンロード

コメント

usingは多段に書くことができますから、
ネストしなくても大丈夫ですよ。


public void Func() {
using (FileStream fs = new FileStream("test.txt", FileMode.Read))
using (StreamReader sr = new StreamReader(fs)) {
try {
// 処理する
}
catch ( Exception e ) {
// 例外処理
System.Diagnostics.Debug.Write(e.StackTrace());
}
}
}

Re: タイトルなし

mssさん、こんばんは。
あっ、確かにそうですね。こうすれば見難くならないですね。
ご指摘ありがとうございました。

コメントの投稿

管理者にだけ表示を許可する

トラックバック

http://csfun.blog49.fc2.com/tb.php/79-a75bd3f7

上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。