私は、正常に動作し、実行時に奇妙なことを示さないプロジェクトをかなりコーディングしました。そこで、静的コード分析ツールを実行することにしました(Visual Studio 2010を使用しています)。ルールCA2000
に違反していることが判明しました。メッセージは次のとおりです。
警告-CA2000:Microsoft.Reliability:メソッド'Bar.getDefaultFoo()'で、オブジェクト' new Foo()'へのすべての参照がスコープ外になる前に、System.IDisposable.Disposeを呼び出します。
参照されるコードは次のようになります。
private static IFoo getDefaultFoo()
{
return (Baz.canIDoIt()) ? new Foo() : null;
}
私は自分自身を考えました:多分条件式はロジック(私のものまたはバリデーターのもの)を台無しにします。これに変更されました:
private static IFoo getDefaultFoo()
{
IFoo ret = null;
if (Baz.canIDoIt())
{
retFoo = new Foo();
}
return ret;
}
同じことが再び起こりましたが、オブジェクトは。と呼ばれるようになりましたretFoo
。私はグーグルで検索し、msdnを実行し、stackoverflowを実行しました。この記事を見つけました。オブジェクトの作成後に実行する必要のある操作はありません。私はそれへの参照を返す必要があるだけです。ただし、OpenPort2の例で提案されているパターンを適用しようとしました。これで、コードは次のようになります。
private static IFoo getDefaultFoo()
{
Foo tempFoo = null;
Foo retFoo = null;
try
{
if (Baz.canIDoIt())
{
tempFoo = new Foo();
}
retFoo= tempFoo;
tempFoo = null;
}
finally
{
if (tempFoo != null)
{
tempFoo.Dispose();
}
}
return retFoo;
}
もう一度同じメッセージですが、tempFoo
今回は変数がルール違反です。つまり、基本的に、コードはねじれ、長く、不合理で、不必要に複雑になり、まったく同じように動作しますが、速度は遅くなります。
同じルールが同様の方法で有効なコードを攻撃しているように見えるこの質問も見つけました。そして、質問者は警告を無視するようにアドバイスされています。私もこのスレッドと同様の質問の塊を読みました。
見逃したことはありますか?ルールにバグがありますか/無関係ですか?私は何をすべきか?無視?魔法のように扱いますか?たぶん、いくつかのデザインパターンを適用しますか?
編集:
ニコールのリクエストに応じて、関連するコード全体を、私も使用してみたフォームで送信しています。
public class DisposableFooTest
{
public interface IFoo
{
void bar();
}
public class Foo : IFoo, IDisposable
{
public void bar()
{
Console.Out.WriteLine("Foo baring now");
}
public void Dispose()
{
// actual Dispose implementation is irrelevant, or maybe it is?
// anyway I followed microsoft dispose pattern
// with Dispose(bool disposing)
}
}
public static class Baz
{
private static bool toggle = false;
public static bool canIDoIt()
{
toggle ^= true;
return toggle;
}
}
private static IFoo getDefaultFoo()
{
IFoo result = null;
try
{
if (Baz.canIDoIt())
{
result = new Foo();
}
return result;
}
catch
{
if (result != null)
{
(result as IDisposable).Dispose();
// IFoo does not inherit from IDisposable, hence the cast
}
throw;
}
}
public static void Main()
{
IFoo bar = getDefaultFoo();
}
}
分析レポートには、次の内容が含まれています。
`CA2000:Microsoft.Reliability:メソッド'DisposableFooTest.getDefaultFoo()'で、System.IDisposable.Dispose on object'result'を呼び出してから、オブジェクトへのすべての参照がスコープ外になります。%% projectpath %% \DisposableFooTest.cs44テスト
Edit2:
次のアプローチでCA2000の問題が解決しました。
private static IFoo getDefaultFoo()
{
Foo result = null;
try
{
if (Baz.canIDoIt())
{
result = new Foo();
}
return result;
}
finally
{
if (result != null)
{
result.Dispose();
}
}
}
残念ながら、私はそのように行くことはできません。さらに、オブジェクト指向の原則、グッドプラクティス、およびガイドラインに従ってコードを簡素化し、読み取り可能、保守可能、および拡張可能にすることを期待しています。誰かが意図したとおりに読んだのではないかと思います。可能であればFooを与えるか、そうでない場合はnullにします。