2012-04-16 5 views
15

Scenariusz: asynchroniczne zadanie w pętli wykonuje metoda zawierająca argumenty, które zmieniają się jak program kontynuuje:Przekazywanie argumentów ze zmianami wartości do Zadanie - Zachowanie?

while(this._variable < 100) 
{ 
    this._variable++; 
    var aTask = Task.Factory.StartNew(() => 
    { 
     aList.add(this._variable); 
     update(this._savePoint); 
    }); 
} 

Jeśli pętla działa szybciej niż zadań kompletnych będzie lista dodać bieżącą wartość zmiennej lub jest zmienna zapisana lokalnie i oryginalna wartość dodana?

+3

Sprawdź to przez Jona Skeeta: http://csharpindepth.com/Articles/Chapter5/Closures.aspx –

+0

+1 doskonałe pytanie! – nawfal

Odpowiedz

11

Zamknięcia blisko zmiennych, a nie wartości. Dlatego zwiększając wartość _variable można zmienić zachowanie zadania, które się do niego odnosi.

Można temu zapobiec poprzez lokalną kopię:

while (this._variable < 100) 
{ 
    this._variable++; 
    int local = _variable; 
    var aTask = Task.Factory.StartNew(() => 
    { 
     aList.add(local); 
     update(this._savePoint); 
    }); 
} 

Albo można przekazać wartość do zadania jako państwa:

while (this._variable < 100) 
{ 
    this._variable++; 
    var aTask = Task.Factory.StartNew(object state => 
    { 
     aList.add((int)state); 
     update(this._savePoint); 
    }, this._variable); 
} 

Są zarówno praca kopiując wartość _variable do nowa zmienna tymczasowa. W pierwszym przypadku zmienna local jest zdefiniowana wewnątrz zakresu pętli, więc dostajesz nową dla każdej iteracji. W drugim przypadku tworzysz kopię wartości _variable po przekazaniu jej do zadania jako argumentu state. Jeśli _variable byłyby typem odniesienia, te rozwiązania nie działałyby; musiałbyś wykonać klon.

+0

Co się stanie, jeśli zmienna jest instancją klasy? 'SomeClass localVariable = this._variable' w pętli. Będąc referencją, w jaki sposób upewnisz się, że nie otrzymasz zmienionego stanu. – asunrey

+1

@Moyler: musiałbyś sklonować instancję wewnątrz pętli, co oznacza, że ​​utworzysz nową instancję i sprawisz, że wartości jej właściwości będą identyczne z właściwościami oryginalnej instancji. –

+0

Dziękuję, potrzebowałem tego potwierdzić. Ponadto pierwotnie miałem na celu, aby mój przykład miał typ referencyjny. Wspaniale jest dostać dwie na jedną transakcję. – asunrey