2

在四处搜索之后,我似乎无法找到 C# 编译器抱怨本地变量dteDest在该行中未分配的原因

if (dteSrc == dteDest) {

如果我更换线路,错误就会消失

DateTime dteSrc, dteDest;

DateTime dteSrc, dteDest = DateTime.MinValue;

据我所见,如果 dteDest 未由作为输出参数的 DateTime.TryParse 初始化,则代码将永远不会到达比较行。

我的逻辑是:

  1. 如果 currentDataObj 为 null 则 booHaveOrigDate 为 false 并且第一个if失败
  2. 如果 currentDataObj 不为 null 但不能转换为 DateTime 则 booHaveOrigDate 为 false 并且第一个if失败
  3. 如果 DateTime.TryParse 无法转换为 DateTime,它将返回 false,这与 && 一起意味着永远不会使用 dteDest。

简单示例代码

void StrangeLogic(object srcData, object currentDataObj) {
   DateTime dteSrc, dteDest;

   bool booHaveNewDate = DateTime.TryParse(srcData.ToString(), out dteSrc);
   bool booHaveOrigDate = (currentDataObj != null) 
                          && DateTime.TryParse(currentDataObj.ToString(), out dteDest);

   if (booHaveNewDate && booHaveOrigDate) {
      if (dteSrc == dteDest) { 
          // Get a "use of unassignned local variable 'dteDest' 
          // unless dteDest = DateTime.MinValue beforehand
      }
   }
}

另外,如果我换行

bool booHaveNewDate = DateTime.TryParse(srcData.ToString(), out dteSrc);

到以下

bool booHaveNewDate = (srcData != null) && DateTime.TryParse(srcData.ToString(), out dteSrc);

然后编译器抱怨 srcDate 也没有分配。

谁能指出我所缺少的正确方向 - 我不是指参数检查等我担心为什么编译器逻辑似乎被使用常见的 TryParse 函数所愚弄?

附加信息

即使扩展逻辑仍然会给出相同的错误(使用未分配的局部变量)

bool booHaveOrigDate;
if (currentDataObj != null) 
   booHaveOrigDate = DateTime.TryParse(currentDataObj.ToString(), out dteDest); 
else 
   booHaveOrigDate = false;

if (booHaveOrigDate) {
    if (dteSrc == dteDest) {

似乎编译器对空值检查 (currentDataObj != null) 所做的任何事情都会阻止它正确确定除非分配,否则不会访问 dteDest

将其更改为此代码并且没有问题(除了空对象上可能的 .ToString()

bool booHaveOrigDate = DateTime.TryParse(currentDataObj.ToString(), out dteDest); 
if (booHaveOrigDate) {
    if (dteSrc == dteDest) {
4

5 回答 5

6

您的替换不正确,应该是:

DateTime dteSrc = DateTime.MinValue, dteDest = DateTime.MinValue;

但是,您应该使用 TryParse 的返回变量,如果您的 booHaveNewDate:

DateTime dteSrc, dteDest;

if(DateTime.TryParse(srcData.ToString(), out dteSrc) && DateTime.TryParse(currentDataObj.ToString(), out dteDest))
{
  if (dteSrc == dteDest) { 
      // Do your stuff here
  }
}

现在您不必在开始时指定日期。

** 您应该在使用前测试此代码,它不是生产代码,可能包含错误

于 2011-10-26T09:05:23.097 回答
3

编译器在形式上是正确的,对dteDest(作为out参数)的赋值是有条件的。在编译器看来,这可能不会发生。编译器不“理解” TryParse() 遵循的逻辑。

这是一个类似的情况:

int f(int x)
{
   int r;

   if (x <= 5)  r = 1;
   if (x >  5)  r = 2;

   return r;  // error: use of uninitialized var
}

在旁注中,初始化似乎稍微合乎逻辑

  DateTime dteSrc = default(DateTime), dteDest = default(DateTime);

但是它是相同的值(DateTime.MinValue)。

于 2011-10-26T09:11:21.807 回答
1

我可能是错的,但我认为编译器在报告此错误时不会尝试广泛剖析您的代码。我目前正在尝试寻找一些资料来支持我的理论。同时,我的猜测是这是一个设计决策,因为如果一个人需要几秒钟以上的时间才能看到一个变量在被初始化之前不会被使用,那么将它初始化为 null 可能是一个更好的编码决策开头是为了避免混淆。

编辑:

好吧,我环顾四周,虽然我发现了几个人说的基本相同的事情,但我找不到任何官方文档说明这一点。以下是我发现的回复:

“编译器完全有权不知道你的逻辑。”

http://www.pcreview.co.uk/forums/use-unassigned-local-variable-error-t3067479.html

“......当有控制流结构时,它无法评估情况,因为它没有执行代码,所以它不知道值是否被分配。”

http://bytes.com/topic/c-sharp/answers/917965-why-am-i-getting-unassigned-local-variable-errors

于 2011-10-26T09:06:28.173 回答
0

dteDest如果currentDataObj == null

如果您将线路更改为:

bool booHaveOrigDate = DateTime.TryParse(currentDataObj != null ? currentDataObj.ToString() : string.Empty, out dteDest);
于 2011-10-26T09:07:01.780 回答
0

编译器逻辑似乎被使用常见的 TryParse 函数所愚弄

上面的问题可以通过以下事实来最容易地回答:当编译器编译您的代码时,它不查看该方法在内部做什么,它只查看签名。它知道它可以返回一个可能为真或假的布尔值,并且它知道它正在设置 的值dteDest

不过,这不是你的问题。问题在于以下行:

bool booHaveOrigDate = (currentDataObj != null) 
          && DateTime.TryParse(currentDataObj.ToString(), out dteDest);

&&如果第一部分为假,则使用不会评估第二部分的运算符。这称为短路评估,其原理是,如果第一部分是错误的,那么第二部分是什么都无关紧要 - 整体结果将永远是错误的。

所以在这种情况下 dteDest 永远不会被设置并且编译器觉得这是一个问题,即使你查看逻辑并说如果没有设置代码将永远不会运行。

一个简单的事实是,人们通常可以发现编译器之外的优化和特殊情况。你听起来好像你已经意识到你可以简单地通过在开始时检查参数然后返回它是否为空来解决这个问题。

于 2011-10-26T09:20:18.427 回答