Входной параметр потока - PullRequest
2 голосов
/ 06 ноября 2011

Я хочу запустить класс с другим значением в списке потоков.как это:

     int index = 0;
     foreach (TreeNode nd in tvew.Nodes[0].Nodes)
     {
         threadping[index] = new Thread(delegate()
         { this.Invoke(new DelegateClientState(InvokeCheckNetworkState), new object[] {nd}); });

         threadping[index].Name = nd.Name;
         threadping[index].IsBackground = true;
         threadping[index].Start();

         index++;
     }

но когда я отлаживаю код, я вижу, что параметр класса - это только последнее значение.Я имею в виду, когда я прохожу класс потока, я вижу, что каждый раз, когда этот класс запускается, значение входного параметра является последним значением для последнего потока.

Кто-нибудь может сказать мне, ПОЧЕМУ?

1 Ответ

5 голосов
/ 06 ноября 2011

Это потому, что переменная nd захвачена в замыкании.Когда потоки запускаются, они все ссылаются на один и тот же экземпляр TreeNode, а именно последний экземпляр, который был назначен nd.Чтобы исправить это, используйте отдельную переменную, которая не изменяется в области видимости:

 foreach (TreeNode nd in tvew.Nodes[0].Nodes)
 {
     var current = nd;
     threadping[index] = new Thread(delegate()
     { this.Invoke(new DelegateClientState(InvokeCheckNetworkState), new object[] {current}); });

Если мы получим технический компилятор, это происходит потому, что компилятор генерирует анонимный класс, содержащий вашу переменную цикла, чтобы сделать егодоступный для потока делегат.Это ожидаемое поведение, хотя, возможно, немного нелогичное, когда вы сталкиваетесь с ним в первый раз.

Для более подробного объяснения замыканий и захвата переменных, см. Раздел «Захваченные переменные» здесьраздел) в статье Джона Скита или этой статьи от Эрика Липперта .Это обычно называется ошибкой «доступа к измененному закрытию».Если вы будете искать этот термин в StackOverflow или Google, вы получите множество обращений, объясняющих его.

...