none
VS2012コード分析 CA2213の対策を教えて下さい。 RRS feed

  • 質問

  • ●環境
    VS2012 C# windows7x64 pro .Net4.5

    ●プロジェクト
    ・メインフォーム(.exe)
    ・補助DLL(.DLL)

    ●使用方法
    メインフォームの参照追加にて、補助DLLを読み込みオブジェクトを生成して使用

    ●補助DLLの役割(の一部※問題の内容のみ記載)
    ・System.Timerを使用し、タイマーイベント発生後イベントを発生させメインフォームに通知する。

    ●問題点
    補助DLLのプロジェクトにてビルドにおけるコンパイルの警告は発生しませんでしたが、コード分析すると
    警告が発生しました。
    原因はSystem.TimerがIDisposableを持っているが、DLLがDisposeをしていないためでした。
    対処するために、補助DLL側にIDisposableを実装しDispose処理を追加することにより、コード分析による警告が解除されましたが
    補助DLLのオブジェクトを生成するメインフレーム側で、コード分析によるCA2213の警告が発生しました。
    発生箇所はDesigner.csに自動生成されるDispose処理のロジックでした。
    補助DLLのDispose呼び出しはForm_Closingのタイミングに記載していましたが、呼ばれない可能性もあるためか警告は消えませんでした。

    ●仮対処
    Designer.csのDispose処理をコメントアウトし、メインフォームに移動し補助DLLのDisposeのコードを追加するとコード分析による警告が消えました。

    ●変更したい点
    ①Designer.csのソースをコメントアウトしたくない
    ②コード分析による警告を消したい

    何か良い修正案はないでしょうか?


    2014年9月17日 17:25

回答

  • フォームから利用する前提の部品であれば、コンポーネント(Componentの派生クラス)として部品を実装してしまうのがおすすめではあります。

    そうするとフォームからデザイナで貼り付け、解放も自動生成されたコードから自動で実行させることができます。

    今の実装でメッセージだけ抑制したいなら、以下のような方法があります。

    SuppressMessageAttrobute
    http://msdn.microsoft.com/ja-jp/library/system.diagnostics.codeanalysis.suppressmessageattribute(v=vs.110).aspx

    • 回答としてマーク mogja 2014年9月18日 4:51
    2014年9月18日 1:12
  • うーんいまいち状況がわかりませんでした。

    ちなみに、独自に IDisposable.Dispose(bool) メソッドを定義した場合、自動生成される Designer.cs から Disposeメソッドは消える(生成されなくなる)ため、特に編集不要かもしれません。Designer.csからcut & pasteで独自コードファイルに移動し、追加コードを書くことはできそうです。

    # 確認はVS2013で行いましたがVS2012でも多分同じだと思います。

    追記:

    もちろんなちゃさんが提案されているようにComponentの派生クラスもしくはIComponentインターフェースを実装した上で、this.components.Add(hoge) とすれば、自動生成されるDispose()メソッドからDisposeが呼び出されます。
    # それによって警告が消えるかどうかは試せませんでした。

    • 編集済み 佐祐理 2014年9月18日 2:34
    • 回答としてマーク mogja 2014年9月18日 4:51
    2014年9月18日 2:31

すべての返信

  • コードが書かれていないので正確には読み取れていませんが、補助DLLがSystem.TimerをnewしているにもかかわらずそれをDispose()していない旨を警告されているのでしょうか?

    であればDispose()できるよう設計を見直すことです。もしかして補助DLLは静的メソッドで設計されていて、Dispose()を呼ぶべきタイミングがないということでしょうか? そうであればその設計に問題があるということになります。オブジェクト指向的にはクラスを用意し、コンストラクターなどでnewをし、そのクラスはIDisposableを実装し、最低限、クラスのDispose()内でTimerのDispose()を呼ぶ必要があります。
    その上で、メインフォーム側が当該クラスをnewしてインスタンスを生成し、メインフォームが責任を持って当該クラスのDispose()を呼ぶことです。

    そうすることで、補助DLL行うべきリソース解放の責務をIDisposableという形でメインフォームに委譲できるわけです。

    もちろん仮対処のように、警告の本質から目を背け、警告を無視したり抑止したりすることもできますが。

    2014年9月17日 22:23
  • フォームから利用する前提の部品であれば、コンポーネント(Componentの派生クラス)として部品を実装してしまうのがおすすめではあります。

    そうするとフォームからデザイナで貼り付け、解放も自動生成されたコードから自動で実行させることができます。

    今の実装でメッセージだけ抑制したいなら、以下のような方法があります。

    SuppressMessageAttrobute
    http://msdn.microsoft.com/ja-jp/library/system.diagnostics.codeanalysis.suppressmessageattribute(v=vs.110).aspx

    • 回答としてマーク mogja 2014年9月18日 4:51
    2014年9月18日 1:12
  • コードが書かれていないので正確には読み取れていませんが、補助DLLがSystem.TimerをnewしているにもかかわらずそれをDispose()していない旨を警告されているのでしょうか?

    であればDispose()できるよう設計を見直すことです。もしかして補助DLLは静的メソッドで設計されていて、Dispose()を呼ぶべきタイミングがないということでしょうか? そうであればその設計に問題があるということになります。オブジェクト指向的にはクラスを用意し、コンストラクターなどでnewをし、そのクラスはIDisposableを実装し、最低限、クラスのDispose()内でTimerのDispose()を呼ぶ必要があります。
    その上で、メインフォーム側が当該クラスをnewしてインスタンスを生成し、メインフォームが責任を持って当該クラスのDispose()を呼ぶことです。

    そうすることで、補助DLL行うべきリソース解放の責務をIDisposableという形でメインフォームに委譲できるわけです。

    もちろん仮対処のように、警告の本質から目を背け、警告を無視したり抑止したりすることもできますが。

    それはわかっているけれども、フォームの自動実装のコード内にDisposeメソッドができてしまうので、自分でカスタマイズできない(自分でNewしたメンバのDispose呼び出しを追加できない)のが原因という話ですね。
    2014年9月18日 1:18
  • うーんいまいち状況がわかりませんでした。

    ちなみに、独自に IDisposable.Dispose(bool) メソッドを定義した場合、自動生成される Designer.cs から Disposeメソッドは消える(生成されなくなる)ため、特に編集不要かもしれません。Designer.csからcut & pasteで独自コードファイルに移動し、追加コードを書くことはできそうです。

    # 確認はVS2013で行いましたがVS2012でも多分同じだと思います。

    追記:

    もちろんなちゃさんが提案されているようにComponentの派生クラスもしくはIComponentインターフェースを実装した上で、this.components.Add(hoge) とすれば、自動生成されるDispose()メソッドからDisposeが呼び出されます。
    # それによって警告が消えるかどうかは試せませんでした。

    • 編集済み 佐祐理 2014年9月18日 2:34
    • 回答としてマーク mogja 2014年9月18日 4:51
    2014年9月18日 2:31
  • ちなみに、独自に IDisposable.Dispose(bool) メソッドを定義した場合、自動生成される Designer.cs から Disposeメソッドは消える(生成されなくなる)ため、特に編集不要かもしれません。Designer.csからcut & pasteで独自コードファイルに移動し、追加コードを書くことはできそうです。

    # 確認はVS2013で行いましたがVS2012でも多分同じだと思います。

    すみません、これは気づいていませんでした。

    これができるならもちろんこれもありですね。

    2014年9月18日 2:41
  • うーんいまいち状況がわかりませんでした。

    ちなみに、独自に IDisposable.Dispose(bool) メソッドを定義した場合、自動生成される Designer.cs から Disposeメソッドは消える(生成されなくなる)ため、特に編集不要かもしれません。Designer.csからcut & pasteで独自コードファイルに移動し、追加コードを書くことはできそうです。

    検討有難う御座います。

    認識があっているか判りませんが、Designer.csからcut & pasteで、Form1.cs(フォーム作成時に自動生成される.csファイル)に移動して、そこにDLL側のDisposeを呼び出すように追加したのが仮対処の方法となっています。

    個人的にはDesigner.csで生成されている物を、別のcsファイルに移動させるのが嫌だったため今回質問に上げた次第です。

    2014年9月18日 4:36
  • フォームから利用する前提の部品であれば、コンポーネント(Componentの派生クラス)として部品を実装してしまうのがおすすめではあります。

    そうするとフォームからデザイナで貼り付け、解放も自動生成されたコードから自動で実行させることができます。

    今の実装でメッセージだけ抑制したいなら、以下のような方法があります。

    サンプル提示有難う御座います。

    フォームからしか使用しない部品の為コンポーネントで対処してみた所、コンパイル・コード分析共に警告が表示されないことが確認出来ました。

    デバッガ動作上もDispose処理が呼ばれ、終了時のログにもDispose関連含めた例外発生は確認されず動作も問題ないと思われます。

    有難う御座いました。


    • 編集済み mogja 2014年9月18日 5:12 追記
    2014年9月18日 4:50