I can't believe I've never come across this before, but why am I getting a compiler error for this code?
public class Main
{
public Main()
{
var ambiguous = new FooBar(1);
var isConfused = ambiguous.IsValid; // this call is ambiguous
}
}
public class FooBar
{
public int DefaultId { get; set; }
public FooBar(int defaultId)
{
DefaultId = defaultId;
}
public bool IsValid
{
get { return DefaultId == 0; }
}
public bool IsValid(int id)
{
return (id == 0);
}
}
Here is the error message:
Ambiguity between 'FooBar.IsValid' and 'FooBar.IsValid(int)'
Why is this ambiguous?
I'm thinking there are two reasons it should not be ambiguous:
- There are no parenthases after
IsConfused
.
- There is no int argument for
IsConfused
.
Where is the ambiguity?
There error is because it is ambiguous since it's declared using var
. It could be:
bool isConfused = ambiguous.IsValid;
Or:
Func<int, bool> isConfused = ambiguous.IsValid;
Using var
requires the compiler to be able to infer the exact meaning, and in this case, there are two possibilities.
However, if you remove the var
, you'll still get a (different) error, since you can't have two members with the same name, one a property, and one a method.
It's confusing you would get that particular message, but it is not legal to have two members with the same name (excepting method overloading). Here your property and method have the same name. This is the same reason you can't have a property and an inner class with the same name. Fields, properties, methods, and inner classes are all members of the enclosing type and must have unique names.
You would get an error that "FooBar already contains a definition for IsValid"
At first, it might seem that the compiler could always figure out whether you're calling the method or using the property -- after all, the method has parentheses after it, and the property doesn't.
That doesn't hold up, though. You can use a method without the parentheses:
void Foo() { ... }
void Bar(Action action) { ... }
Bar(Foo);
And you can use a property with parentheses:
Action MyProperty { get; set; }
MyProperty();
The only way to make sure there's no ambiguity is to disallow having a method and a property with the same name.