roslyn: is not SomeType fails to compile if there is a member with the same name
Version Used: .NET 5.0 C# 9 Visual Studio 2019 version 16.8.4
Add the following type:
public class SomeType
{
public int SomeProperty { get; init; }
}
You can use both is SomeType
and is not SomeType
in a class without a member called SomeType
.
// Compiles
public class Version1
{
public void Execute(object data)
{
if (data is SomeType)
Console.WriteLine("data is SomeType");
else
Console.WriteLine("data is not SomeType");
}
}
// Compiles
public class Version2
{
public void Execute(object data)
{
if (data is not SomeType)
Console.WriteLine("data is not SomeType");
else
Console.WriteLine("data is SomeType");
}
}
However, in a class containing a member called SomeType
, is SomeType
compiles, but is not SomeType
does not compile.
/// Compiles
public class Version3
{
private string SomeType => "some type";
public void Execute(object data)
{
if (data is SomeType)
Console.WriteLine("data is SomeType");
else
Console.WriteLine("data is not SomeType");
}
}
// Fails to compile with error CS0428.
public class Version4
{
private string SomeType => "some type";
public void Execute(object data)
{
if (data is not SomeType)
Console.WriteLine("data is not SomeType");
else
Console.WriteLine("data is SomeType");
}
}
Currently, version 4 fails to compile with error CS0428. The issue occurs when there is a static or non-static field, property, or method called SomeType
. Workarounds are to change the member SomeType
to any other name or to fully qualifying the type as in is not SomeNamespace.SomeType
.
Given that version 3 compiles, I would also expect version 4 to compile without these workarounds.
About this issue
- Original URL
- State: closed
- Created 3 years ago
- Comments: 25 (16 by maintainers)
Does seem like a bug. The behavior is not limited to
not
but also extends toand
andor
.Need to discuss in LDM / compat council before we consider fixing this. Too late in 16.9 to take a change like this so punting out to 16.10.
Generally this is not done because it is not a sustainable pattern. Consider that every such mode must be tested in combination with each other. That gets unsustainable very quickly.
I error’d by mentioning compat council in my first comment here. This feature RTM’d with 16.9 which means we’re not even in the first update yet. Compat decisions don’t begin to take hold firmly for close to a year after RTM. We just need to confirm with LDM that this is the intended behavior and if so clarify the spec plus fix the bug.
IIRC, Color-Color is pretty similar to the situation in the issue description.
i.e. inside the class
Widget
, when do you pick the typeColor
or the memberColor
.This is not a bug.
is Type
is the is-type construct, not pattern-matching.is not Type
is an is-pattern operation. Pattern-matching and is-type necessarily have different binding rules. For compatibility, the former must bind to a type if one exists, even if it would be shadowed by a constant, which means it skips other members during lookup. The latter can match to other members, so its name lookup rules do not skip members and do not prioritize a type. We could not use the same rules for pattern-matching because that would (among other things) break the Color-Color situation. Similarly forand
andor
. This is one of the areas where we could not fully hide the seam between compatibility with existing constructs and extending the language to use the “same” syntax for extended functionality.