为什么这个(null | | ! TryParse)条件导致“使用未赋值的局部变量”?

以下代码导致 使用未分配的局部变量“ numberOfgroups”:

int numberOfGroups;
if(options.NumberOfGroups == null || !int.TryParse(options.NumberOfGroups, out numberOfGroups))
{
numberOfGroups = 10;
}

但是,这段代码工作得很好(尽管 锐利者= 10是多余的) :

int numberOfGroups = 10;
if(options.NumberOfGroups == null || !int.TryParse(options.NumberOfGroups, out numberOfGroups))
{
numberOfGroups = 10;
}

是我遗漏了什么,还是编译器不喜欢我的 ||

我已经把范围缩小到导致问题的 dynamic(options在我上面的代码中是一个动态变量)。问题仍然存在,为什么我不能这么做

编译代码 没有:

internal class Program
{
#region Static Methods


private static void Main(string[] args)
{
dynamic myString = args[0];


int myInt;
if(myString == null || !int.TryParse(myString, out myInt))
{
myInt = 10;
}


Console.WriteLine(myInt);
}


#endregion
}

然而,这个代码 是的:

internal class Program
{
#region Static Methods


private static void Main(string[] args)
{
var myString = args[0]; // var would be string


int myInt;
if(myString == null || !int.TryParse(myString, out myInt))
{
myInt = 10;
}


Console.WriteLine(myInt);
}


#endregion
}

我没想到 dynamic也是其中一个因素。

2996 次浏览

From MSDN (emphasis mine):

The dynamic type enables the operations in which it occurs to bypass compile-time type checking. Instead, these operations are resolved at run time. The dynamic type simplifies access to COM APIs such as the Office Automation APIs, and also to dynamic APIs such as IronPython libraries, and to the HTML Document Object Model (DOM).

Type dynamic behaves like type object in most circumstances. However, operations that contain expressions of type dynamic are not resolved or type checked by the compiler.

Since the compiler does not type check or resolve any operations that contain expressions of type dynamic, it cannot assure that the variable will be assigned through the use of TryParse().

I am pretty sure this is a compiler bug. Nice find!

Edit: it is not a bug, as Quartermeister demonstrates; dynamic might implement a weird true operator which might cause y to never be initialized.

Here's a minimal repro:

class Program
{
static bool M(out int x)
{
x = 123;
return true;
}
static int N(dynamic d)
{
int y;
if(d || M(out y))
y = 10;
return y;
}
}

I see no reason why that should be illegal; if you replace dynamic with bool it compiles just fine.

I'm actually meeting with the C# team tomorrow; I'll mention it to them. Apologies for the error!

It's possible for the variable to be unassigned if the value of the dynamic expression is of a type with an overloaded true operator.

The || operator will invoke the true operator to decide whether to evaluate the right-hand side, and then the if statement will invoke the true operator to decide whether to evaluate the its body. For a normal bool, these will always return the same result and so exactly one will be evaluated, but for a user-defined operator there is no such guarantee!

Building off of Eric Lippert's repro, here is a short and complete program that demonstrates a case where neither path would be executed and the variable would have its initial value:

using System;


class Program
{
static bool M(out int x)
{
x = 123;
return true;
}


static int N(dynamic d)
{
int y = 3;
if (d || M(out y))
y = 10;
return y;
}


static void Main(string[] args)
{
var result = N(new EvilBool());
// Prints 3!
Console.WriteLine(result);
}
}


class EvilBool
{
private bool value;


public static bool operator true(EvilBool b)
{
// Return true the first time this is called
// and false the second time
b.value = !b.value;
return b.value;
}


public static bool operator false(EvilBool b)
{
throw new NotImplementedException();
}
}