2009-12-03 12 views
8

Der idomatic Weg, eine neue nebenwirkungs nur Aufgabe zu starten (das heißt: eine Aufgabe, die kein Ergebnis zurückgibt) 4.0 mit dem TPL in .NET wird die folgende API:Warum ist die TaskFactory.StartNew-Methode nicht generisch?

Task Task.Factory.StartNew(Action<object>, object) 

Aber warum doesn‘ schauen t Unterzeichnung dieses API wie dieses

Task Task.Factory.StartNew<T>(Action<T>, T) 

oder ähnliche

Task Task.Factory.StartNew<T>(T, Action<T>) 

technischen Gründen oder aus einem anderen Grund?

Antwort

7

Okay, jetzt, dass ich die Frage richtig zu verstehen :)

Ich glaube, es ist, weil dies ein direct replacement for ThreadPool.QueueUserWorkItem sein soll. Ich stimme zu, dass es etwas seltsam scheint ... aber wenn Sie Lambda-Ausdrücke verwenden sowieso, ist es wahrscheinlich einfacher, die Version zu verwenden, dass tut einen Zustandsparameter nehmen (dh Action statt Action<object>) und erfassen nur den Wert Du bist daran interessiert. Es hilft nicht, wenn Sie den Wert und die Funktion separat angeben :(

+1

Ja, aber Task ist generisch im Ergebnistyp (TResult) einer Task, aber nicht generisch im Typ des "initial state" (dh die Eingabe für eine Task). – Frank

+0

Also ... Wenn ich Task.Factory.StartNew aufrufen greift es automatisch einen Thread aus dem Threadpool? –

+0

@Padu: Ja, ich glaube schon - obwohl Sie Ihre eigene Task Factory haben können, die eine andere Reihe von Threads verwendet, glaube ich. –

3

Nach einem Beitrag von Stephen Toub (MSFT), gehen sie davon aus, dass wir auf Schließungen angewiesen sind, um Zustandsdaten zu übergeben (http://social.msdn.microsoft.com/Forums/en/parallelextensions/thread/1988294c-de41-476a-a104-aa550b7409f5)

Sich auf Schließungen zu verlassen, um dieses Problem zu lösen, scheint jedoch ein temporärer Hack zu sein, der auf eine bessere Lösung wartet.Es funktioniert, aber es ist keine gute längerfristige Lösung viele Male, dass einfach eine delegierte Methode als Aktion spezifizieren wäre die einfachste Ansatz sein, aber das bedeutet, dass wir globale vars verwenden haben oder wir aus dem Zustand Parameterübergabe ausgeschlossen.

I wie einer von Hugos Vorschlägen (aus dem MS-Forum-Posting). Hugo schlug vor, einen TaskState-Typ einzuführen, der wie ein cleverer Weg erscheint, das Problem der Mehrdeutigkeit von Generika zu umgehen.

Angewandt auf die Task.Factory.StartNew() Unterschrift und der Aufgabe() Konstruktor als solche:

public Task<T>(Action<T> function, TaskState<T> state); 
    public Task<T,TResult>(Func<T,TResult> function, TaskState<T> state); 

Actionstate viel wie die Nullable-Klasse sein würde - nur ein einfacher Wrapper um einen Wert Mitglied. In der Praxis könnte mit Taskstate wie folgt aussehen:

var myTask = new Task(MyMethod, new TaskState(stateInfo)); 
    ... 

    public void MyMethod(StateInfo stateInfo) { ... } 

Die Taskstate <> Lösung ist nicht perfekt, aber es scheint wie eine viel bessere Lösung als beim Schließen des Typs Gießen verlassen.

+0

+1 Interessant, danke. – Frank

+2

Lustig, das TPL-Team hat soeben ein [White Paper] (http://blogs.msdn.com/b/pfxteam/archive/2011/11/10/10235962.aspx) über die Verbesserungen in 4.5; in dem „best practices“ Abschnitt (p. 11), beschreiben sie, dass es am besten ist, in dem Zustand explictly ( Überlastung über die Aktion) zu übergeben, anstatt Variablen in der Schließung der Erfassung.Im Hinblick auf diese Empfehlung wäre eine generische Überlastung sicherlich wünschenswert. – Frank

Verwandte Themen