2010-12-05 5 views
1

Wie würden Sie Instanzreferenzen an eine neue Aufgabe senden/weitergeben?C# - UI-Referenz an Task.Factory.StartNew() senden?

Sagen wir, ich habe dies:

public BlockingCollection<string> blockingCollection = new BlockingCollection<string>(); 
    textBox_txt.Text = "Result: "; 
    public Task t = Task.Factory.StartNew(() => 
    { 
     foreach (string value in *???1*.blockingCollection.GetConsumingEnumerable()) 
     { 
      *???1*.blockingCollection.Take() 
      [...bla...] 
      *???2*.Invoke(new updateTextBox_txtCallback(*???2*.updatetextBox_txt) 
          , new object[] { "THE RESULT!\r\n" }); 
     }     
    }); 

ich, dass irgendwo raten bin hier StartNew(() => Ich habe die Hinweise auf die blockingContent und zum textBox passieren. Ich habe mich umgesehen, konnte aber die Syntax nicht herausfinden. (es ist ziemlich haarig)

Hilfe, bitte.

[Bearbeiten] Also, wenn ich ein statisches Objekt von der Aufgabe aufrufen, funktioniert es offensichtlich; aber ich brauche die Aufgabe, um mit Instanzen zu arbeiten; nämlich die blockingCollection und die updateTextBox_txtCallback Invoke.

Antwort

1

Ich reproduziert Ihr Problem, mit einem Workaround unten. Das Problem besteht darin, dass Sie den Task als ein Feld in Ihrer Klasse verwenden, sodass er sich nur auf statische Member beziehen kann, da die Instanz erst beim Ausführen des Konstruktors erstellt wurde (die Feldinitialisierer werden vor der Initialisierung der Klasse aufgerufen). Von der C# Spezifikation (10.5.5.2):

Eine Variable Initialisierer für eine Feldinstanz kann die Instanz nicht Referenz geschaffen. Somit ist es ein Kompilierzeitfehler dieses in einer Variablen Initialisierer zu referenzieren, wie es ist Kompilierzeitfehler für eine variable Initialisierer jede Instanz Element durch einen einfachen Namen zu referenzieren. In der Beispielklasse A {int x = 1; int y = x + 1; // Fehler, Referenz auf Instanzmitglied dieser} die Variable Initialisierer für y ergibt einen Fehler bei der Kompilierung, weil ein Mitglied der Instanz referenziert, die erstellt wird.

Grundsätzlich haben Sie zwei Möglichkeiten:

  1. initialisieren Ihre Aufgabe Variable im Konstruktor
  2. Verwenden Sie ein Verfahren stattdessen zum Abruf

Beispiel:

public class Foo 
{ 
    public string myProperty = "foobar"; 
    public Task t; 

    public Foo() 
    { 
     t = Task.Factory.StartNew(() => 
     { 
      myProperty = "test"; 

     }); 
    } 

    //THIS won't compile 
    //public Task t = Task.Factory.StartNew(() => 
    //{ 
    // myProperty = "test"; 

    //}); 

    public Task GetTask() 
    { 
     Task t = Task.Factory.StartNew(() => 
     { 
      myProperty = "test"; 

     }); 
     return t; 
    } 
} 
+0

Ich weiß für eine Tatsache (getestet), dass eine Möglichkeit, die UI von einem anderen Thread (wie einem BgWorker) zu aktualisieren ist, Invoke und eine Callback-Funktion zu verwenden ; was ich getan habe * 2 *. Invoke (new updateTextBox_txtCallback (* ??? 2 *. updatetextBox_txt), neues Objekt [] {"DAS ERGEBNIS! \ r \ n"}; 'Wenn es ein BgWorker wäre, das * 2 wäre durch "dieses" ersetzt worden. aber in meinem aktuellen Fall brauche ich die Instanzreferenz des Hauptthreads. – Spectraljump

+0

@Twodordan: bearbeitet meine Antwort auf das Problem zu zeigen – BrokenGlass

+0

Ich sah, und Sie vorübergehend "meinen Arsch gerettet"; Wie jetzt kann ich weiterschreiben, während ich auf eine Antwort warte. Vielen Dank! – Spectraljump

1

Sie müssen die Referenz nicht übergeben, da C# closures unterstützt. Einfach mit der Variable, dass die Bezugnahme in Ihrem StartNew Block die Compiler Code zu generieren verursachen halten, die Sie in Statusobjekt Referenzpakete auf, die auf die anonyme Methode übergeben wird:

textBox_txt.Text = "Result: "; 
public Task t = Task.Factory.StartNew(() => 
{ 
    // use textBox_txt in this block - the compiler 
    // will handle the passing of actual reference to the 
    // anonymous method for you     
}); 

I The Beauty of Closures auf diesem für weitere Informationen empfehlen Feature.

Nun, ob es eine gute Idee ist, über einen Wert zu schließen, der ein Verweis auf ein UI-Element ist, ist eine völlig andere Diskussion.

+0

Das funktioniert nicht.Ich brauche die Referenzen, sonst bekomme ich "ein Feldinitialisierer kann nicht auf ein nicht statisches Feld verweisen" oder "existiert nicht im aktuellen Kontext". – Spectraljump

+0

Dieser Fehler muss von woanders kommen - ich sehe nichts in dem von Ihnen geposteten Code, der dieses Problem verursachen würde. –

+0

Wenn ich die 'public BlockingCollection' in' public STATIC BlockingCollection' setze, funktioniert es; aber ich kann (und möchte nicht) statische vars in meinem code haben. Das Gleiche gilt für die TextBox. Es lässt mich nicht einfach schreiben, ohne zu sagen, woher es kommt. – Spectraljump