Вот моя ситуация:
interface Icontainer{
string name();
}
abstract class fuzzyContainer : Icontainer{
string name(){
return "Fuzzy Container";
}
}
class specialContainer: fuzzyContainer{
string name(){
return base.name() + " Special Container";
}
}
Icontainer cont = new SpecialContainer();
cont.name(); // I expected "Fuzzy Container Special Container" as the output.
Когда я работаю, мой код, как описано выше вывода является просто "Нечетким Контейнером". Что я пропускаю здесь? Существует ли лучший способ получить желаемые результаты?
Если вы сделаете name () virtual
, а затем переопределите
в specialContainer, вы получите ожидаемое поведение.
public interface Icontainer
{
string name();
}
public abstract class fuzzyContainer : Icontainer
{
public virtual string name()
{
return "Fuzzy Container";
}
}
public class specialContainer : fuzzyContainer
{
public override string name()
{
return base.name() + " Special Container";
}
}
Во-первых, это полезно, когда у вас есть вопросы, когда вы публикуете код, который действительно компилируется. Трудно проанализировать проблему, когда она полна пропущенных модификаторов и опечаток, трудно понять, является ли проблема опечаткой или нет.
Как только мы выполним работу по исправлению вашей программы, чтобы она действительно компилировалась, компилятор выдает предупреждение о том, что перегрузка выглядит неправильно . Поскольку ваш вопрос - "почему неправильная перегрузка?" Вероятно, было бы неплохо прочитать предупреждение компилятора, которое мы выпустили, чтобы вы могли проанализировать эту проблему.
Проблема в том, что производный класс содержит новый метод с именем «name», а не переопределение существующего метода. Это то, что вам пытается сказать предупреждение.
Есть два способа решить эту проблему, в зависимости от того, вы предполагали, что метод будет «новым» или «переопределенным». Если вы намеревались «переопределить» метод, сделайте базовую реализацию виртуальной, а производную реализацию - переопределением.
Если вы предполагали, что метод будет «новым» и , вы все равно хотите, чтобы новый метод заменил привязку к реализации интерфейса , тогда используйте повторную реализацию интерфейса :
class SpecialContainer: FuzzyContainer, IContainer
{
public new string Name()
{
return base.Name() + " Special Container";
}
}
Обратите внимание на "новый" и тот факт, что мы повторно заявили , что этот класс реализует IContainer. Это говорит компилятору «игнорировать привязки к методам IContainer, выведенные из базового класса, и начать заново."
Это потому, что вы скрываете метод, а не переопределяете его. Не сделав базовый метод виртуальным, невозможно его переопределить, но вы можете "спрятать" его, создав одноименный метод.
Если у вас было:
SpecialContainer cont = new SpecialContainer();
cont.name();
Тогда вы также получите ожидаемый результат.
Ответ Мэтта также работает и может быть предпочтительнее, если вы можете отредактировать базовый класс, чтобы сделать метод виртуальным. По умолчанию методы не переопределяются, если они явно не помечены как таковые с помощью ключевого слова virtual
Метод name в этом классе не является переопределением метода FuzzyContainer Name. Поэтому, когда вы приводите объект specialContainer в качестве IContainer, он может вызывать только метод Name базового класса.
Вам нужно объявить имя-метод виртуальным и переопределить его в производном классе.
Я также взял на себя смелость "подправить" ваш код в соответствии с наиболее распространенными соглашениями об именовании.
abstract class FuzzyContainer : IContainer{
protected virtual string GetName(){
return "Fuzzy Container";
}
}
class SpecialContainer: FuzzyContainer{
override string GetName(){
return base.GetName() + " Special Container";
}
}