【发布时间】:2015-12-27 14:56:07
【问题描述】:
以下 C# 程序产生意外输出。我希望看到:
值1:25,值2:10
值1:10,值2:25
但我看到了
值1:0,值2:10
值1:10,值2:25
namespace ConsoleApplication4
{
class Program
{
static void Main(string[] args)
{
DoWork().Wait();
Console.ReadLine();
}
private async static Task DoWork()
{
SomeClass foo = new SomeClass()
{
MyValue = 25.0f
};
PrintTwoValues(foo.MyValue, await GetValue());
PrintTwoValues(await GetValue(), foo.MyValue);
}
static void PrintTwoValues(float value1, float value2)
{
Console.WriteLine("Value1: {0}, Value2: {1}", value1, value2);
}
static Task<float> GetValue()
{
return Task.Factory.StartNew(() =>
{
return 10.0f;
});
}
class SomeClass
{
private float myValue;
public float MyValue
{
get
{
return this.myValue;
}
set
{
this.myValue = value;
}
}
}
}
}
有人可以向我解释为什么在 PrintTwoValues 方法的第二个参数的表达式中使用“await”运算符似乎会影响第一个参数的值吗?
我的猜测是它一定与参数列表是从左到右进行评估的事实有关。在对PrintTwoValues 的第一次调用中,我猜测SomeClass.MyValue 的返回值会被推入堆栈。然后继续执行到GetValue,它只是启动任务并退出。然后DoWork 退出并安排一个将调用PrintTwoValues 的延续,但是当该延续运行时,最初压入堆栈的值不知何故丢失并恢复为默认值。
虽然有一些简单的方法可以解决此问题,例如在将参数传递给 PrintTwoValues 方法之前将它们存储在临时变量中,但我主要只是好奇为什么会发生这种行为。
注意:我使用的是 Visual Studio 2013 Update 5。我正在构建一个面向 .NET Framework 4.5 并在 Windows 10 Enterprise 上运行的控制台应用程序。
【问题讨论】:
-
我得到了你期望得到的。
-
调试/发布模式下的行为是否改变?
-
有趣。我没有在发布模式下尝试过。看起来我确实在 Release 中得到了预期的结果,但在 Debug 中没有。
-
@StephenCleary 此处相同,但我可以在 VS2013 和 LinqPad 4 中重现。有趣的是,LinqPad 5 没有问题。我以为是 .Net Framework 版本,但是将 VS2015 降到 4.5 并没有出现问题。那么也许它与 C# 5 有关?
-
@PauloMorgado,使用
Task.Run并没有什么不同。但是,感谢您指向该文章的指针。我不知道Task.Factory.StartNew的危险。
标签: c# parameters arguments async-await parameter-passing