В вашем коде C # есть ошибка.
Чтобы переопределить функцию C #, вам нужно указать ключевое слово override
.
Если вы напишете снова virtual
, вы создаете теневую копию базовой функции, но без ключевого слова new
вы должны получить предупреждение.
Если оба объявлены виртуальными, у вас есть две функции с одинаковым именем!
Давайте сделаем пример ...
public class Base
{
public Base() { fun(); }
public virtual void fun() { Console.Write(1); }
}
public class Derived : Base
{
public Derived() { fun(); }
public override void fun() { Console.Write(2); }
}
public class DerivedWithError : Base
{
public DerivedWithError() { fun(); }
public new virtual void fun() { Console.Write(3); }
}
...
// This will print "22".
Base normal = new Derived();
Console.WriteLine();
// This will print "13" !!!
Base withError = new DerivedWithError ();
Console.WriteLine();
// Let's call the methods and see what happens!
// This will print "2"
normal.fun();
Console.WriteLine();
// This will print "1" !!!
withError.fun();
Console.WriteLine();
Затенение означает «добавить новый метод с тем же именем без использования полиморфизма».
Без ключевого слова override
вы отключаете полиморфизм.
Так что теперь все должно быть чисто и понятно.
DerivedWithError.fun () - это совершенно новый виртуальный метод. У него то же имя, что и у функции fun в базовом классе, но они не связаны!
Говоря с точки зрения виртуальной таблицы (или таблицы виртуальных методов, если вы предпочитаете другое имя), с затенением базовая функция и производная функция занимают две разные записи в виртуальной таблице, даже если они имеют одинаковое имя ,
Если вместо этого вы используете override
, вы заставляете метод func в производном классе перезаписывать запись виртуальной таблицы, занятую Base.func, и это полиморфизм.
Опасно, но разрешено .NET, будьте осторожны с синтаксисом, всегда!
Вы можете вызывать виртуальные функции в конструкторах в C #, однако, как правило, в производном классе, если метод вызывается в базовом конструкторе, вы должны быть осторожны при использовании полей в производном классе.
Теперь, чтобы быть чистым и избежать путаницы и риска, вы должны избегать вызова виртуальных методов в конструкторах, но на самом деле это очень полезно несколько раз.
Например, так называемые «фабричные методы», которые не имеют доступа ни к одной переменной.
public abstract class MyClass
{
public IList<string> MyList { get; private set; }
public MyClass()
{
this.MyList = this.CreateMyList();
}
protected abstract IList<string> CreateMyList();
}
public class MyDerived : MyClass
{
protected override IList<string> CreateMyList()
{
return new ObservableCollection<string>();
}
}
Это совершенно законно и работает!