Вопрос

I have this rather simple logic:

class Program
{
    static void Main(string[] args)
    {
        using (TransactionScope ts = new TransactionScope())
        {
            System.Threading.Tasks.Parallel.Invoke(() =>
                {
                    TransactionScope y = ts;
                    System.Diagnostics.Debug.WriteLine("Test");
                },
                () =>
                {
                    System.Diagnostics.Debug.WriteLine("Test");
                }
            );
            ts.Complete();
        }        
    }
}

If you place breakpoints on the two Debug.WriteLine() statements, you'll notice that when it breaks on the first, both y and ts are listed as locals by the debugger. But when it hits the breakpoint in the latter, ts is not listed as a local and furthermore, adding ts to the watch window gives The name 'ts' does not exist in the current context.

Is this variable capturing in action or is this some other mechanism? I've looked around at writeups on variable capture and I can't find anything that explicitly states that variables are only captured when they're used, but I'm making the assumption that it's called variable capture because it only "captures" what it needs and doesn't keep references to everything available.

Это было полезно?

Решение

I'm making the assumption that it's called variable capture because it only "captures" what it needs and doesn't keep references to everything available

That's exactly right. The compiler refactors code that closes over a variable to keep it in scope. It doesn't close over every single outer variable when an anonymous method is used.

Take the following example:

public static void Foo()
{
    int i = 0;
    int j = 1;
    Action a = () => Console.WriteLine(i);
}

It will be turned into something like the following by the compiler:

public class ClosureClass1
{
    public int i;

    public void Method1()
    {
        Console.WriteLine(i);
    }
}

public static void Foo()
{
    ClosureClass1 closure = new ClosureClass1();
    closure.i = 0;
    int j = 1;
    Action a = closure.Method1;
}

You should be able to see, from this example, why the closed over fields are accessible and the fields not closed over from an outer scope are not.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top