2016-06-14 2 views
4

От here У меня есть что-то равное в моем коде. Скажем, у меня есть следующий класс:Неоднозначность между объектом и методом

public class EList<T> : List<T> 
{ 
    public string Add { get; set; } 
} 

теперь я ожидающей ошибку

Неоднозначность между 'EList.Add' и 'EList.Add (INT)'

но следующий код работает без ошибок:

EList<int> il = new EList<int>(); 
il.Add(1); 
il.Add = "test"; 

Вопрос: Сохраняет ли наследование это e rror по ошибке?

ответ

4

Он явно обслуживается правилами поиска членов C# (C# Specification, раздел 7.4).В частности, важно здесь

возможности ссылки

пропуская ранее правила

  • Далее, если член вызывается, все не Invocable элементы удаляются из набора. (Вызов Add() вызывается. Поэтому Add свойство удаляется из набора)

  • Далее, члены, которые скрыты другими членами удаляются из набора. Для каждого SM-членов в наборе, где S представляет собой тип, в котором М элемент объявленный, применяются следующие правила:

    • Если М является константа, поле, свойство, событие, или член перечисления, то все члены, объявленные в базовом типе S, удаляются из набора. (Метод Add в базовом типе удаляется) больше

правила

Таким образом, на данный момент, никакой неоднозначности, так как выше двух правил не устранили один или другой из потенциально конфликтующие члены.

Смотрите также раздел 10.3, члены класса:

Имя постоянного, поля, свойства, события или типа должны отличаться от имен всех остальных членов объявлены в же класса.

Название метода должно отличаться от имен всех других не-методов, объявленных в , таким же классом. Кроме того ...

(Мой акцент)

И

Наследуемые члены класса типа (§10.3.3) не являются частью декларации пространства класс. Таким образом, производному классу разрешено объявлять член с тем же именем или сигнатурой как унаследованный член

+0

спасибо, это самый правдоподобный и лучший документированный ответ – fubo

2

Ваш код на самом деле выдает предупреждение:

Предупреждение CS0108 шкура 'EList.Add' унаследовал элемент 'List.Add (T). Используйте новое ключевое слово, если было предназначено скрытие.

Здесь нет двусмысленности. il.Add(1); (из-за ()) - вызов метода. Поэтому компилятор ищет метод с именем Add. il.Add = "test"; (из-за =) - свойство setter call. Поэтому компилятор ищет свойство с именем Add.

Так что кажется, что Add свойство переопределить Add метод. А затем il.Add(1); и il.Add = "test"; звонки выбирают наилучшее подходящее решение.

+4

При создании метода и свойства в том же классе с тем же именем вы получите сообщение об ошибке. OP спрашивает, почему ошибка не возникает в случае наследования. –

+1

, если это было бы причиной, тогда это скомпилировалось бы: 'public class EList2 {public string Add {get; задавать; } public void Добавить (int x) {}} ' – fubo

2

Здесь нет никакой двусмысленности, поскольку свойство Add определено в дочернем классе, но метод Add существует в вашем родительском классе. Неоднозначность существует только там, где у вас есть члены с тем же именем в одном классе. Здесь объект, который вы создали, имеет тип EList, и вы ссылаетесь на него переменной типа EList, поэтому компилятор знает, что существует один метод Add, определенный в родительском классе. Аналогичный случай также имеет свойство Add.

Даже если вы определили еще один метод Add в EList, там будет какая-либо ошибка, просто предупреждение о том, что вы скрываете уже реализованный элемент из вашего базового класса.

Это дает более подробной информации MSDN

Интуитивному действие правил разрешения описанному выше выглядит следующим образом: Для того, чтобы найти конкретный метод вызывается с помощью вызова метода, начните с указанным типом с помощью вызова метода и продолжить цепочку наследования до тех пор, пока не будет найдено хотя бы одно применимое, доступное, не-переопределение метода. Затем выполните разрешение перегрузки в наборе применимых, доступных, не переопределенных методов, объявленных в этом типе, и вызовите выбранный таким образом метод.

Смежные вопросы