2013-09-24 204 views
0

我有这个简单的逻辑:范围和匿名方法

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(); 
     }   
    } 
} 

如果放在两个Debug.WriteLine()语句断点,你会发现,当它打破第一,无论是yts被列为调试器的当地人。但是,当它击中后者中的断点,ts不被列为本地,此外,加入ts到监视窗口给The name 'ts' does not exist in the current context.

这个变量捕捉动作或这是一些其他的机制呢?我查阅了关于变量捕获的书写,我找不到任何明确指出变量只在使用时被捕获的东西,但我假设它被称为变量捕获,因为它仅“捕获”了什么它需要并且不保留对可用的一切的引用。

+0

我认为在可能的并行操作完成之前,写入的代码可能有在调用'Complete'的危险。 – Kit

+0

@Kit,从Parallel.Invoke文档:'这种方法不会返回,直到每个提供的操作已完成,无论是否由于正常或异常终止发生完成。“ – Pete

+0

哦,呵呵。我忘了这个。感谢您的提醒。 – Kit

回答

3

我正在做的假设,这就是所谓的变量捕捉,因为它只有“捕捉”它需要什么,不保持引用可用

一切完全正确。编译器重构关闭一个变量的代码,以保持它的作用域。当使用匿名方法时,它不会关闭每个外部变量。

看看下面的例子:

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

它会变成什么样由编译器执行以下操作:

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; 
} 

你应该能够看到,从这个例子,为什么关闭可以访问字段,并且没有从外部作用域关闭的字段不可用。

+0

添加没有捕获变量的lambda也是更好的例子。 '[CompilerGenerated] private void CompilerGeneratedName() { Debug.WriteLine(“Test”); }'在同一类Enclosing Type中 –