コードインスペクション: 破棄されたキャプチャ変数へのアクセス
まず、 クロージャ(英語)とは何かを理解していることを確認しましょう。 簡単に言うと、C# のクロージャは、ラムダ式または外部スコープからいくつかの変数をキャプチャーする匿名メソッドです。 最も簡単な例を次に示します。
// A self-contained lambda. Not a closure.
Action printOne = () => { Console.WriteLine("one"); };
// A closure – a lambda that captures a variable from an outer scope.
string myStr = "one";
Action print = () => { Console.WriteLine(myStr); };
上記の例では、 print は変数 myStr (その 値ではなく)をキャプチャーし、 print() を呼び出したときにのみ myStr の 値を取得します。
より複雑なシナリオでは、クロージャが変化するコンテキストで定義されると、期待通りに動作しないことがあります。
起こりうる状況の 1 つは、 using ステートメント内で定義されたクロージャです。
void Foo(string fileName, string text)
{
using (var writer = new StreamWriter(fileName))
{
ExecuteDelayed(() => { writer.Write(text); });
}
}
private static void ExecuteDelayed(Action action)
{
// execute action
}
上記のコードでは、ReSharper は 破棄されたクロージャへのアクセス警告を writer.Write(text); に対して発行します。 その理由は、 writer のスコープが破棄された後に ExecuteDelayed() がラムダを実行でき、実行時例外が発生する可能性があるためです。
ExecuteDelayed() がスタック上のラムダの処理を完了した場合は、 action パラメーターに InstantHandle 属性を付けてマークすることができます。
private static void ExecuteDelayed([InstantHandle]Action action)
{
// execute action
}
これは ReSharper のコード解析エンジンに、そのような文脈で ExecuteDelayed() を使用することが安全であると伝え、警告は発生しません。
2026 年 6 月 12 日