素晴らしい質問です。キャプチャされた変数とクロージャー コンテキスト。これを逆コンパイルすると、現在のコンパイラが次の2 つのキャプチャ コンテキスト オブジェクトを作成することがわかります。
public void SomeMethod(int someValue, List<int> someValues)
{
Task task;
<>c__DisplayClass3 class2; // <== compiler generated type; unpronounceable
<>c__DisplayClass1 class3; // <== compiler generated type; unpronounceable
class3 = new <>c__DisplayClass1(); // outer-scope context
class3.someValue = someValue;
task = null;
class2 = new <>c__DisplayClass3(); // <== inner-scope context
class2.CS$<>8__locals2 = class3; // <== bind the contexts
class2.anotherValue = 2;
class2.valuesRef = someValues;
task = new Task(new Action(class2.<SomeMethod>b__0));
task.Start();
return;
}
目的がコンテキスト オブジェクトを最小化することである場合は、クロージャを手動で実行できます。
public void SomeMethod2(int someValue, List<int> someValues)
{
Task generatedTask = null;
{
var ctx = new MyCaptureContext();
ctx.anotherValue = 2;
ctx.valuesRef = someValues;
ctx.someValue = someValue;
generatedTask = new Task(ctx.SomeMethod);
}
generatedTask.Start();
}
class MyCaptureContext
{
// kept as fields to mimic the compiler
public int anotherValue;
public int someValue;
public object valuesRef;
public void SomeMethod()
{
anotherValue += someValue + GetSum(valuesRef);
Console.WriteLine(anotherValue);
}
}
状態を個別に渡す単一のデリゲートをキャッシュすることで、タスクごとのデリゲートの作成を回避することもできます。
public void SomeMethod(int someValue, List<int> someValues)
{
Task generatedTask = null;
{
var ctx = new MyCaptureContext();
ctx.anotherValue = 2;
ctx.valuesRef = someValues;
ctx.someValue = someValue;
generatedTask = new Task(MyCaptureContext.SomeMethod, ctx);
}
generatedTask.Start();
}
class MyCaptureContext
{
// kept as fields to mimic the compiler
public int anotherValue;
public int someValue;
public object valuesRef;
public static readonly Action<object> SomeMethod = SomeMethodImpl;
private static void SomeMethodImpl(object state)
{
var ctx = (MyCaptureContext)state;
ctx.anotherValue += ctx.someValue + GetSum(ctx.valuesRef);
Console.WriteLine(ctx.anotherValue);
}
}
または(クリーナー、IMO):
public void SomeMethod(int someValue, List<int> someValues)
{
Task generatedTask = null;
{
var ctx = new MyCaptureContext();
ctx.anotherValue = 2;
ctx.valuesRef = someValues;
ctx.someValue = someValue;
generatedTask = ctx.CreateTask();
}
generatedTask.Start();
}
class MyCaptureContext
{
// kept as fields to mimic the compiler
public int anotherValue;
public int someValue;
public object valuesRef;
public Task CreateTask()
{
return new Task(someMethod, this);
}
private static readonly Action<object> someMethod = SomeMethod;
private static void SomeMethod(object state)
{
var ctx = (MyCaptureContext)state;
ctx.anotherValue += ctx.someValue + GetSum(ctx.valuesRef);
Console.WriteLine(ctx.anotherValue);
}
}