Как может возникнуть двусмысленность между методом getter и методом с одним аргументом?

Не могу поверить, что я никогда не сталкивался с этим раньше, но почему я получаю ошибку компилятора для этого кода?

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);
    }
}

Вот сообщение об ошибке:

Неоднозначность между 'FooBar.IsValid' и 'FooBar.IsValid(int)'

Почему это неоднозначно?

Я думаю, что есть две причины, почему это не должно быть двусмысленным:

  • После IsConfused нет парафаз.
  • Нет аргумента int для IsConfused.

Где двусмысленность?

Ответ 1

Ошибка возникает из-за неоднозначности, поскольку она объявлена ​​с помощью var. Это может быть:

bool isConfused = ambiguous.IsValid;

Или:

Func<int, bool> isConfused = ambiguous.IsValid;

Использование var требует, чтобы компилятор мог определить точное значение, и в этом случае есть две возможности.

Однако, если вы удалите var, вы по-прежнему получите (другую) ошибку, так как вы не можете иметь двух членов с тем же именем, одно свойство и один метод.

Ответ 2

Сбив с толку, вы получите это конкретное сообщение, но неправомерно иметь двух членов с тем же именем (кроме перегрузки метода). Здесь ваше свойство и метод имеют одно и то же имя. Это по той же причине, что вы не можете иметь свойство и внутренний класс с тем же именем. Поля, свойства, методы и внутренние классы являются членами входящего типа и должны иметь уникальные имена.

Ответ 3

Вы получите сообщение об ошибке "FooBar уже содержит определение для IsValid"

Ответ 4

Во-первых, может показаться, что компилятор всегда мог выяснить, вы вызываете метод или используете свойство - в конце концов, после этого метод имеет круглые скобки, а свойство не имеет.

Это не задерживается. Вы можете использовать метод без круглых скобок:

void Foo() { ... }
void Bar(Action action) { ... }

Bar(Foo);

И вы можете использовать свойство с круглыми скобками:

Action MyProperty { get; set; }

MyProperty();

Единственный способ убедиться в отсутствии двусмысленности в том, чтобы запретить использование метода и свойства с тем же именем.