2009年12月03日
FxCopに学ぶ番外編(7) : Dispose メソッドから基本クラスの破棄を呼び出します
メールマガジン「C#プログラミングレッスン」では、今、[FxCopに学ぶ編] を連載中です。
そこで取上げようとしたルールで、下書きまでしたのですが、結局メルマガには書かないことにしたルールがいくつかあります。
そのまま捨ててしまうのはもったいないので、ブログに掲載します。
■IDisposableの実装(3)■
「CA2215:Dispose メソッドから基本クラスの破棄を呼び出します」
というルールがあるのですが、どのようなコードを書いたらこの FxCopの警告が出るのが試したのですが、警告を出すことができません でした。
ということで、いきなりですが、Disposeパターンを実装したクラスを継承する場合の正しいコードを掲載します。
もちろん、DelivedTypeの中で、破棄すべきフィールドを保持していた場合の コードになります。
Disposeパターンを実装したクラスを継承する場合は、 publicな、Disposeメソッドは 継承元で定義済みですので、改めてここで記述する必要はありません。
上記のように、引数ありのDisposeメソッドをoverrideするだけです。
このメソッドの中で継承元の Dispose(disposing) メソッドを忘れずに呼ぶようにします。
■FxCopのルール
CA2215:Dispose メソッドから基本クラスの破棄を呼び出します
2009年11月29日
FxCopに学ぶ番外編(6) : IDisposable を正しく実装します
メールマガジン「C#プログラミングレッスン」では、今、[FxCopに学ぶ編] を連載中です。
そこで取上げようとしたルールで、下書きまでしたのですが、結局メルマガには書かないことにしたルールがいくつかあります。
そのまま捨ててしまうのはもったいないので、ブログに掲載します。
■IDisposableの実装(2)■
前回の続き
まず、なぜ、以下のクラスは、sealedを付加して継承できないようにしないと いけないのでしょうか?
前回のクラスを再度示します。
たとえば、Sampleを継承した、DelivedSampleを考えてみます。
このクラスにも、Dispoaseしないといけないフィールドが存在したとしましょ う。そうなると、必然的に、IDisposableインターフェースを実装しないとい けません。
しかし、このコードは、派生元のDisposeメソッドを隠すことになってしまい ます。
これだと、派生元のTextReaderオブジェクトを破棄することができませ ん。
つまり、Sampleクラスは、継承に対応していないクラスということになり ます。sealedを付けることで、表面上はこの問題を解決することができます。
無理やりコンパイルを通したとしても、以下のようなコードを書くと、
ポリモーフィズムが働きませんので、派生クラスDelivedSampleのDisposeメソ ッドが呼ばれず、DelivedSampleが保持しているリソースを破棄することがで きなくなってしまいます。
では、継承にも対応したクラスをお見せしましょう。
このコードの肝は、
- 複数回、Disposeが呼ばれても問題が発生しない。
- Finalaizeメソッド(デストラクタ)を実装することで、DIsposeを呼び出さなかった 場合でも、ガベージコレクション時にクリーンアップ処理をしている。
- Dispose を呼び出した場合は、GC.SuppressFinalize を呼び出し、 ファイナライズメソッドの呼び出しを抑制している。 (ファイナライズでやることは、すでにDisposeでやっているから不要ということ)
- 実際のクリーンアップ処理を受け持つ、virtualで引数ありのDisposeメソ ッドを用意している。これで継承に対応可能。
これは、Disposeパターンと呼ばれているものです。詳しくは、
http://msdn.microsoft.com/ja-jp/library/fs2xkftw.aspx
をご覧ください。
■FxCopのルール
CA1063: IDisposable を正しく実装します
2009年11月26日
FxCopに学ぶ番外編(5) : 破棄できるフィールドは破棄します
メールマガジン「C#プログラミングレッスン」では、今、[FxCopに学ぶ編] を連載中です。
そこで取上げようとしたルールで、下書きまでしたのですが、結局メルマガには書かないことにしたルールがいくつかあります。
そのまま捨ててしまうのはもったいないので、ブログに掲載します。
■IDisposableの実装(1)■
このコードの問題点はなんでしょうか?
それは、Sampleクラスが IDisposableインターフェースを実装していないこと が問題です。
とIDisposableを指定する必要があります。なぜIDisposableを実装しないと いけないのでしょうか。
それは、reader フィールドのTextReaderクラスがIDisposableを実装している クラスだからです。
TextReaderが使い終わったら、Dispose()メソッドを呼び出しリソースを解放する必要がありますが、それをど こでもやっていません。
どこでTextReaderクラスのDispose()を呼び出せばよいのでしょうか。Execや、Exec2メソッドの中でしょうか。 そうではありませんよね。
利用者側が、Execを呼び出さなかったら、Disposeはされないままですからね。
こんな時には、Sampleクラスにも、Disposeメソッドを定義し、Sampleクラス を利用する側から、Disposeを呼び出してもらえばいいのです。
それが以下のコードです。
使う側が、
とすれば、usingブロックを抜ける時に、Sample.Dispose()が呼ばれ、その中 で、TextReader.Disposeが呼ばれます。
これで、めでたしめでたし...
ではありません。実は、このコードはFxCopでは警告が出てしまいます。
この警告を手っ取り早く回避するには、
と sealed クラスにします。
しかし、sealedにするということは、このクラスから継承させることができな いということです。では継承を許し、かつ、IDisposableを実装するにはどう したら良いのでしょうか?
それは次回に解説します。
■FxCopのルール
CA2213: 破棄できるフィールドは破棄します
2007年07月10日
StreamWriter
.NET Framework の System.IO.StreamWriterって、Disposeメソッドを持っているにも関わらず、IDisposableインターフェースじゃないんですよね。
何でだろう?
単なるバグでしょうか?
追記(訂正)7/12
StreamWriterは、ちゃんと IDisposableインターフェースでした。m(_ _)m
いったい、何を勘違いしていたんでしょうか?
さらに追記 7/12 21:42
StreamWriterを使ったソースを見てみると、
※ sealed なのd、DisposeはこれでOK.
って書いてあって、usingを使うようなコードじゃない。
他のソースで、Disposeメソッドを使っているところを検索してみたけど、
みんな、上記のような使いばかりで、
のように書いている箇所はなかった。
なんで、あんな勘違いをしたのか、良く思いだせない...
何でだろう?
単なるバグでしょうか?
追記(訂正)7/12
StreamWriterは、ちゃんと IDisposableインターフェースでした。m(_ _)m
いったい、何を勘違いしていたんでしょうか?
さらに追記 7/12 21:42
StreamWriterを使ったソースを見てみると、
internal sealed class MySample : IMySample, IDisposable {
private StreamWriter _writer;
public FileStatusManager() {
...
_writer = new StreamWriter(filename, true);
}
public void Dispose() {
_writer.Dispose();
}
}※ sealed なのd、DisposeはこれでOK.
って書いてあって、usingを使うようなコードじゃない。
他のソースで、Disposeメソッドを使っているところを検索してみたけど、
みんな、上記のような使いばかりで、
Xxxx xx = new Xxxx();
...
xx.Dispose();
のように書いている箇所はなかった。
なんで、あんな勘違いをしたのか、良く思いだせない...



