The following code results in use of unassigned local variable "numberOfGroups":
int numberOfGroups;
if(options.NumberOfGroups == null || !int.TryParse(options.NumberOfGroups, out numberOfGroups))
{
numberOfGroups = 10;
}
However, this code works fine (though, ReSharper says the = 10
is redundant):
int numberOfGroups = 10;
if(options.NumberOfGroups == null || !int.TryParse(options.NumberOfGroups, out numberOfGroups))
{
numberOfGroups = 10;
}
Am I missing something, or is the compiler not liking my ||
?
I've narrowed this down to dynamic
causing the issues (options
was a dynamic variable in my above code). The question still remains, why can't I do this?
This code doesn't compile:
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
}
However, this code does:
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
}
I didn't realize dynamic
would be a factor in this.
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();
}
}
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()
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With