Okay, so the C# Language Specification has a special section (old version linked) on the Color Color
rule where a member and its type has the same name. Well-known guru Eric Lippert once blogged about it.
The question I am going to ask here is in a sense (not) quite the same that was asked in the thread Circular definition in a constant enum. You can go and upvote that other question if you like.
Now for my question. Consider this code:
namespace N
{
public enum Color
{
Green,
Brown,
Purple,
}
public class C1
{
public const Color Color = Color.Brown; // error CS0110 - WHY? Compiler confused by Color Color?
}
public class C2
{
public static readonly Color Color = Color.Brown; // fine
}
public class C3
{
public static Color Color = Color.Brown; // fine
}
public class C4
{
public Color Color = Color.Brown; // fine
}
}
The point here is that in each situation above, the right-most identifier Color
can refer either to the enum
type, or to the class member with the same name. But the Color Color
rule mentioned above means that we should see if the member (Brown
) is static or non-static. Since it is static in this case, we should interprete Color
accordingly.
My obvious main question: Why does this not work with a const
type member? Is this unintended?
(Obviously, saying N.Color.Brown
(N
is the namespace) "fixes" it; I am not asking about that!)
Side note: With local variable const
, the above anomaly does not exist:
public class C5
{
public Color Color;
void M()
{
const Color Color = Color.Brown; // works (no warning for not using local variable?)
}
}
public class C6
{
public Color Color;
void M()
{
const Color other = Color.Brown; // works (warning CS0219, 'other' not used)
}
}
It is a bug. I am unable to reproduce the problem in CTP 5 of VS 2015, and I think this one should have been fixed as part of the Roslyn rewrite. However, a commenter below notes that they can reproduce it in CTP 6. So I'm not sure what is going on here as far as whether this bug has been fixed or not.
On a personal note: I do not specifically recall if I was tasked with looking into this one when it was first reported back in 2010 but since I did quite a bit of work on the circularity detectors around then, odds are pretty good.
This is far from the only bug there was in the circularity detectors; it would get quite confused if there were nested generic types which in turn had generic base types whose type arguments involved the nested types.
I am not at all surprised that Alex "won't fix"ed this one; I spent quite a long time rewriting the code that did class circularity detection and the change was deemed too risky. All that work was punted to Roslyn.
If you're interested to see how the Color Color binding code works in Roslyn, take a look at the aptly-named method BindLeftOfPotentialColorColorMemberAccess
-- I love me some descriptive method names -- in Binder_Expressions.cs
.