2012-07-26 57 views
3

我的代码中的任务(t)不能在我的代码中直接在我的代码中使用。我得到以下错误:动作委托内的任务实例

代码:

Task t = Task.Factory.StartNew(() => 
{ 
    MessageBox.Show(t.Id.ToString()); 
}); 

现在,如果我做了以下工作:

Task t = null; 
t = Task.Factory.StartNew(() => 
{ 
    MessageBox.Show(t.Id.ToString()); 
}); 

可能有人请解释为什么是这样的话?

回答

4

C#编译器不知道什么关于Task.Factory.StartNew。就编译器而言,在调用StartNew之后,包括t被分配之前的任何时间,可以在任何时间访问t

您的第二个代码片段有竞争条件:如果并发线程上的任务在分配完成之前转到显示消息框,您将看到空引用异常。

试试这个实验:

private static Task Wrapper(Action f) { 
    var res = Task.Factory.StartNew(f); 
    Thread.Sleep(1000); 
    return res; 
} 

现在用的Wrapper在你的第二个片段的调用替换Task.Factory.StartNew直接通话,并观看了程序崩溃。

Task t = null; 
t = Wrapper(() => { 
    MessageBox.Show(t.Id.ToString()); 
}); 
+0

这两个片段(在问题中)具有相同的竞争条件。但编译器不知道,错误来自静态分析。 – 2012-07-26 11:22:59

+0

@HenkHolterman是的,它仍然存在。这个想法是为了使比赛条件更加明显。 – dasblinkenlight 2012-07-26 11:23:29

+0

很好的解释,谢谢。那么,在代理中访问我的任务实例有没有安全的方法? – davenewza 2012-07-26 11:24:38

2

您必须首先为t分配一个值,以便它获得对Task类型的对象的引用。

在你的第一批代码中,你尝试给t赋一个值并​​在一个语句中使用它(在那里只有一个分号)。

在第二个示例中,这些是两个单独的语句,因此它将起作用。