Я изучаю C#, и я встретился со следующей проблемой. У меня есть два класса: базируйтесь и полученный:
class MyBase
{
public void MyMethod()
{
Console.WriteLine("MyBase::MyMethod()");
}
}
class MyDerived: MyBase
{
public void MyMethod()
{
Console.WriteLine("MyDerived::MyMethod()");
}
}
На данный момент, без virtual
и override
ключевые слова. Когда я компилирую это, я получаю предупреждение (который, конечно, ожидается), что я пытаюсь скрыться MyMethod
от MyBase
класс.
То, что я хочу сделать, должно назвать метод от базового класса, имеющего экземпляр производного класса. Я делаю это как это:
MyDerived myDerived = new MyDerived();
((MyBase)myDerived).MyMethod();
Это хорошо работает, когда я не указываю никого virtual
, и т.д. ключевые слова в методах. Я пытался поместить комбинацию ключевых слов, и я получил следующие результаты:
| MyBase::MyMethod | MyDerived::MyMethod | Result printed on the console |
| -----------------|---------------------|-------------------------------|
| - | - | MyBase::MyMethod() |
| - | new | MyBase::MyMethod() |
| virtual | new | MyBase::MyMethod() |
| virtual | override | MyDerived::MyMethod() |
Я надеюсь, что таблица ясна Вам. У меня есть два вопроса:
((MyBase)myDerived).MyMethod();
)? Я знаю о base
ключевое слово, но это можно назвать только с внутренней части производного класса. Действительно ли это правильно?virtual
и override
модификаторы), метод, который назвали, прибыл из производного класса? Объясните это? Когда вы вызываете виртуальный
метод для экземпляра типа, который переопределяет метод, всегда будет вызываться переопределенная версия, даже если вы приведете к базовому классу.
Единственный способ вызвать базовую реализацию виртуального метода в классе, который переопределяет метод, - это создать второй метод в производном классе (не в базовом классе), который вызывает метод с использованием base
] ключевое слово.
В общем, необходимость сделать это является признаком плохой разработки API - если вы думаете, что вам нужно вызвать базовую версию, производная версия, вероятно, должна иметь другое имя.
Вы правы - base
можно вызывать только из производного класса - Source .
На этой странице также приведен пример того, как переопределить определение базового класса.
Что касается вашего второго вопроса, вы меняете не тип объекта, на который вы ссылаетесь, а только интерфейс, через который вы на него ссылаетесь. Поэтому, если у вас есть объект B, который наследуется от A и переопределяет функцию C, даже если вы ссылаетесь на B как на A, он все равно вызывает реализации наиболее производного типа, в данном случае B.
base
ссылается на в базовый класс для данного экземпляра. Между прочим, старайтесь избегать написания кода, обеспечивающего соблюдение принципа подстановки, другими словами, не пишите код, который зависит от реализации вашей иерархии классов, потому что вам придется изменить этот код, если вы добавите новый производный класс для вашего базового класса.