2013-09-24 4 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 перечислены locals отладчиком. Но когда она попадает в точку останова в последней, 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

Добавление лямбда без захваченной переменной также в качестве примера будет еще лучше. '[CompilerGenerated] private void CompilerGeneratedName() { Debug.WriteLine (" Test "); } 'В том же классе типа корпуса –

Смежные вопросы