Как может быть двусмысленность между получателем свойства и методом с одним аргументом?

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

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)»

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

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

  1. После IsConfused скобок нет.
  2. Для IsConfused нет аргумента int.

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


person devuxer    schedule 07.07.2011    source источник


Ответы (4)


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

bool isConfused = ambiguous.IsValid;

Or:

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

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

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

person Reed Copsey    schedule 07.07.2011
comment
Также есть ошибка, потому что вам просто не разрешено определять двух членов с одинаковым именем :) - person Jon Skeet; 07.07.2011
comment
Было ли это ограничение введено в действие с .Net 1? - person Yuriy Faktorovich; 07.07.2011
comment
@Jon: Да, очень верно. Но ошибка, которую он отображает, - это двусмысленность из-за var... Я тоже отредактировал, чтобы упомянуть об этом. - person Reed Copsey; 07.07.2011
comment
@Yuriy: Да, хотя это сообщение новее, поскольку var не существовало в .NET 1. Вторая ошибка, которую я упомянул, была бы той, которую он получил бы в ранних версиях .NET. - person Reed Copsey; 07.07.2011
comment
@Reed Copsey - Тогда, если имена будут изменены, двусмысленности не будет. Я не думаю, что это правильный ответ. - person manojlds; 07.07.2011
comment
@Jon Skeet @Reed Copsey - Я тут запутался. Конечно, VS отображает ошибку неоднозначности, но компиляция дает только одну ошибку, и я думаю, что только последняя должна быть правильной, потому что, если ошибка с несколькими членами исправлена, двусмысленности вообще не было бы. - person manojlds; 07.07.2011
comment
@manojlds: используя компилятор C # 4 с этим кодом, я получаю только ошибку Тип «FooBar» уже содержит определение для «IsValid». - person Jon Skeet; 07.07.2011
comment
@manojlds: компилятор не всегда показывает вам ВСЕ ошибки - часто это так, но часто он останавливается при обнаружении ошибки. Если вы измените var на bool в своей строке, как это предполагает, вы увидите вторую ошибку. - person Reed Copsey; 07.07.2011
comment
@Jon Skeet - именно это я и говорю. Итак, VS делает что-то не так, отображая другую ошибку, верно? - person manojlds; 07.07.2011
comment
@manojlds: Используете ли вы инструмент повышения производительности, например Resharper/JustCode/CodeRush? Если это так, вероятно, инструмент сообщает о неправильной ошибке... - person Reed Copsey; 07.07.2011
comment
@Jon, @manojlds: механизм, который определяет ошибки по мере того, как вы печатаете, ведет себя несколько иначе, чем механизм, который определяет ошибки во время сборки. . В частности, первый пытается справиться с ситуациями, когда код неверен, потому что он активно редактируется. В таких случаях у нас есть эвристики, которые пытаются обнаружить и предотвратить каскадные ошибки, когда устранение одной ошибки вызывает другую; это может быть странным и непредвиденным поведением одной из этих эвристик. - person Eric Lippert; 07.07.2011
comment
@Reed, +1 и спасибо за ваш ответ и дополнения. Я не думаю, что написал выражение Func без использования лямбда, поэтому сценарий, о котором вы упомянули, никогда бы не пришел мне в голову. Интересный материал. - person devuxer; 08.07.2011
comment
Ошибка возникает, несмотря на то, что свойства напрямую скомпилированы в методы получения/установки с именем PropertyName_get. Это просто означает, что на уровне IL у вас может быть такая ситуация с омонимичным методом/свойством, потому что вы компилируете метод в IsValid(int) и свойство в IsValid_get(), который все еще является методом! - person usr-local-ΕΨΗΕΛΩΝ; 20.03.2013

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

person Kirk Woll    schedule 07.07.2011
comment
Я думаю, вы поняли, +1. Я получал ошибку только на Main (но не на FooBar), но когда я закомментировал оскорбительную строку в Main и скомпилировал, я получил ошибку для FooBar ("Foobar" уже содержит определение для IsValid). Странно, что ошибка в main перекрывает ошибку в FooBar. - person devuxer; 07.07.2011
comment
@DanM - Другая ошибка не рассматривается. Когда я компилирую, я получаю только другую ошибку, только VS отображает обе ошибки. - person manojlds; 07.07.2011
comment
@DanM: это не для меня при компиляции из командной строки. Вам подходит точно этот код? - person Jon Skeet; 07.07.2011
comment
@Jon Skeet, @manojlds, ребята, вы правы. Я получаю только ошибку о неоднозначности (красная волнистая линия) перед сборкой, но после сборки ошибка неоднозначности исчезает, и я получаю только уже содержащую ошибку определения (синяя волнистая линия). - person devuxer; 07.07.2011
comment
Однако технически свойства ЯВЛЯЮТСЯ функциями, поэтому это сбивает с толку. В системе Java Getter/Setter таких проблем нет. Хорошее объяснение, +1. - person Nyerguds; 10.04.2013
comment
@Nyerguds, было бы точнее сказать, что свойства состоят из одной или нескольких функций. Они являются первоклассными гражданами C# (в отличие от Java). Другими словами, имена свойств могут конфликтовать с именами других членов, и подразумеваемые методы получения и установки могут также конфликтовать с именами членов. Вот почему int Foo { get; set; } и int get_Foo() { return 0; } также вызовут столкновение. - person Kirk Woll; 10.04.2013
comment
@KirkWoll: вау. Сгенерированный код добавляется во время компиляции и никогда не показывается пользователю... как восхитительно непрозрачно. - person Nyerguds; 11.04.2013
comment
@Nyerguds, в C# их огромное количество, от замыканий до деревьев выражений и т. д. - person Kirk Woll; 11.04.2013

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

person manojlds    schedule 07.07.2011
comment
Как ни странно, я не знаю, пока не построю. Я получаю только ошибку о двусмысленности (красная закорючка). Как только я строю, ошибка неоднозначности исчезает, и я уже получаю сообщение об ошибке определения (синяя волнистая линия). Может ли это быть ошибкой в ​​​​Visual Studio? - person devuxer; 07.07.2011
comment
@DanM - это то, о чем я спрашивал в комментариях к ответу @Reed Copsey. VS, похоже, ведет себя здесь неправильно. На самом деле, VS показывает обе ошибки, компиляция показывает только ошибку множественного определения, что и должно было показывать VS. - person manojlds; 07.07.2011
comment
@manojlds: вопрос в том, почему вы получили это сообщение, если параметры разные? Мне кажется, что это простое перегруженное имя. - person Nyerguds; 10.04.2013

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

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

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

Bar(Foo);

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

Action MyProperty { get; set; }

MyProperty();

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

person Joe White    schedule 07.07.2011
comment
Однако вы не можете использовать свойство со скобками, если его результат уже определен как логическое значение. - person Nyerguds; 10.04.2013
comment
Прежде всего, это относится только к одной из ситуаций, когда это неоднозначно. Но, во-вторых, вы хотите взять возможную функцию (разрешить свойствам иметь те же имена, что и методы), которая не очень полезна для начала, и сделать ее менее полезной, разрешив ее только тогда, когда свойство имеет определенные типы? Помните, что каждая функция начинается с минус 100 баллов. Вы не представляете очень убедительный случай. - person Joe White; 11.04.2013