Doskonałe pytanie; przechwycone zmienne i konteksty zamknięcia. Dekodowanie to pokazuje, że obecny kompilator tworzy kontekst przechwytywania obiektów tutaj:
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;
}
Jeśli twoim celem jest zminimalizowanie obiektów kontekście można wykonać zamknięcia ręcznie:
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);
}
}
Można również unikać tworem pełnomocnik per zadanie poprzez buforowanie jeden pełnomocnik, która przechodzi w stan oddzielnie:
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);
}
}
lub (cle Aner, 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);
}
}
Najlepszym sposobem zrozumienia jest zbadanie wyniku kompilacji. Możesz go zdekompilować i zbadać. –
Kod dekompilowany został opublikowany przez Marc :) –