2013-09-24 172 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中 –