I just bumped into a really strange C# behavior, and I’d be glad if someone could explain it to me.
Say, I have the following class:
class Program
{
static int len = 1;
static void Main(string[] args)
{
Func<double, double> call = len => 1;
len = 1; // error: 'len' conflicts with the declaration 'csutils.Program.len'
Program.len = 1; // ok
}
}
As I get it, in the line of commentary I have the following objects in my field of view: len
variable and call
.
Inside of lambda, I have local parameter len
and Program.len
variable.
However, after declaring such lambda, I cannot use len
variable in the scope of Main
method anymore. I have to either refer to it as to Program.len
either rewrite lambda to be anyOtherNameBesidesLen => 1
.
Why is it happening? Is this correct behavior of language, or I’ve encountered a bug in the language? If this is correct behavior, how is it justified by the language architecture? Why is it okay for lambda capture variable to mess with code outside lambda?
Edit: Alessandro D'Andria has got quite nice examples (number 1 and 2 in his comment).
edit2: This code (equal to the one I wrote at the beginning) is illegal:
class Program
{
static int len = 0;
static void Main(string[] args)
{
{
int len = 1;
}
int x = len;
}
}
This code however, despite having exactly the same scope structure, is perfectly legal:
class Other
{
static int len = 0;
class Nested
{
static void foo()
{
int len = 1;
}
static int x = len;
}
}
As far as I can see, it is correct to emit a compile-time error in this case because it is not permissible to use len
in a child scope (namely the parameter of the anonymous function (lambda)) when the same symbol len
without qualification is used (for something else) in a containing scope within the same method.
However, the error text is confusing.
If you change to:
static int len = 1;
static void Main(string[] args)
{
len = 1;
Func<double, double> call = len => 1; // error CS0136: A local variable named 'len' cannot be declared in this scope because it would give a different meaning to 'len', which is already used in a 'parent or current' scope to denote something else
}
the error text is better.
Some other examples:
static int len = 1;
static void Main()
{
var len = 3.14; // OK, can hide field
Console.WriteLine(len); // OK, 'len' refers to local variable
Console.WriteLine(Program.len); // OK, hidden field can still be accessed, with proper qualification
}
The above example shows that it is fine to hide a field with an identically named local variable (or method parameter) as long as the field is always accessed with qualification (after a .
member access operator).
static int len = 1;
static void Main()
{
if (DateTime.Today.DayOfWeek == DayOfWeek.Saturday)
{
var len = 3.14;
Console.WriteLine(len);
}
Console.WriteLine(len); // error CS0135: 'len' conflicts with the declaration 'csutils.Program.len'
}
This shows that it is not possible to hide len
in a child scope when you try to use the field len
in the parent scope. Again the error text can be criticized.
static int len = 1;
static void Main()
{
Console.WriteLine(len);
if (DateTime.Today.DayOfWeek == DayOfWeek.Saturday)
{
var len = 3.14; // error CS0136: A local variable named 'len' cannot be declared in this scope because it would give a different meaning to 'len', which is already used in a 'parent or current' scope to denote something else
Console.WriteLine(len);
}
}
You see the analogy.
Of course these issues have been mentioned many times before here on SO, an example being Why can't a duplicate variable name be declared in a nested local scope?
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