The issue is the lifetime of the variable vs. the lifetime of the address taken in the lambda in which it's used. The compiler can ensure that the variable itself lives as long as the lambda (because it's stored in a separate hidden class, due to the capturing), but the address itself (which could be copied somewhere else after the fact) may live longer than the variable, and thus would refer to an address that is no longer valid.
Note that this contrasts with variables captured and used as ref
or out
parameters. For example:
class Program
{
static void Main(string[] args)
{
int x;
Thread t = new Thread(() => { sum(12, 6, out x); });
}
static void sum(int a, int b, out int p)
{
p = a + b;
}
}
The above is allowed, because the captured variable will be moved from the stack to a separate class that holds it, and that class's lifetime can be ensured to be at least as long as the delegate that will use it.
The unsafe
throws a monkey wrench into the works. Unlike ref
and out
, which have semantics that the compiler can enforce and always use safely, pointers can be stored in arbitrary ways, and the compiler has no way to ensure the lifetime of those pointers. So, even if it captures the x
variable to a hidden class like it would in other situations, it still can't guarantee that class remains live for at least as long as the address.
Your specific example is theoretically safe, because the address isn't actually stored anywhere and is used immediately by the method that the anonymous methods calls. But the compiler can't guarantee that safety, and so prohibit any taking of the address of the captured variable.