2014-01-06 51 views
0

我已将此标记为.NET 4,因为我使用的是async BCL使用具有异步功能的异步BCL

我有以下代码:

using System.Threading.Tasks; 

public static async Task<ObservableCollection<MyResult>> GetMyData(Params p) 
{ 
    DoStuffClass stuff = new DoStuffClass(); 
    ObservableCollection<MyResults> results = null; 

    await Task.Factory.StartNew(() => 
    { 
     results = stuff.LongDrawnOutProcess(p); 
    }); 

    return results; 
} 

我从以前的版本看起来是这样的重构:

static void GetMyDataAsync(Params p, EventHandler<MyArgs> callback) 
{ 
    DoStuffClass stuff = new DoStuffClass(); 
    stuff.LoadCompleted += callback; 
    stuff.LongDrawOutProcessAsync(p) 
} 

这个灵感来自here

到目前为止,第一种情况的使用是最简单的,这就是为什么我重构;我的问题是:这种方法有什么缺陷吗? LongDrawnOutProcess确实击中了数据库。

回答

6

您应该使用任务的Result来访问Task的结果,而不是依赖任务设置其他变量的副作用。虽然在这种情况下,您没有太早访问结果,但使用这种编程风格时很容易犯错误。您还需要考虑是否存在适当的记忆障碍,以便能够正确观察到变化的变量。

更优选的方法是这样的:

public static async Task<ObservableCollection<MyResult>> GetMyData(Params p) 
{ 
    DoStuffClass stuff = new DoStuffClass(); 

    return await Task.Factory.StartNew(() => stuff.LongDrawnOutProcess(p)); 
} 

接下来,因为你永远不会做任何await东西后,除了返回一个值,还有在这里使用async根本没有真正的理由;你可以写:

public static Task<ObservableCollection<MyResult>> GetMyData(Params p) 
{ 
    DoStuffClass stuff = new DoStuffClass(); 

    return Task.Factory.StartNew(() => stuff.LongDrawnOutProcess(p)); 
} 

最后,这确实有一个更基本的问题。您没有使用实际的异步方法。你正在创建一个线程池线程,它将花费所有的时间来等待这个方法的完成。这是浪费,而异步编程的设计是为了避免这种同步等待,而不是将它们推到另一个线程。如果你希望你的程序是台异步你还是应该使用Async方法,但你仍然可以把它转换成异步的基于任务的风格的好处:

static Task<ObservableCollection<MyResult>> GetMyDataAsync(Params p) 
{ 
    var tcs = new TaskCompletionSource<ObservableCollection<MyResult>>(); 
    DoStuffClass stuff = new DoStuffClass(); 
    stuff.LoadCompleted += (args) => tcs.TrySetResult(args.Result); 
    stuff.LongDrawOutProcessAsync(p); 
    return tcs.Task; 
} 
+0

此行不会编译,因为没有结果属性。 stuff.LoadCompleted + =(args)=> tcs.TrySetResult(args.Result); 我不清楚到底在做什么 - 它只是设置事件处理程序? –

+1

@ pm_2我不知道你班级的活动实际上是什么样子。这个想法只是简单地从事件的参数中获得操作的结果,并相应地设置TCS的结果。 – Servy

+0

对不起,你说得很对......无论如何,这可能是自己问题的主题。非常感谢您的帮助 –