Методы, которые реализованы из интерфейса, не виртуальные по умолчанию.Вы просто предоставляете реализацию контракта, определенного в определении интерфейса.Помечая метод как virtual
, вы разрешаете производным классам предоставлять дополнительную или отдельную реализацию, все еще соблюдая контракт, как определено.
Рассмотрите этот пример:
interface IAnimal
{
string Speak();
}
class Dog : IAnimal
{
public string Speak()
{
return "Bark!";
}
}
* Dog
класс реализует интерфейс, предоставляя реализацию контракта IAnimal
.Здесь нет виртуальных методов и переопределений.
Теперь рассмотрим этот пример:
interface IAnimal
{
string Speak();
}
class Dog : IAnimal
{
public virtual string Speak()
{
return "Bark!";
}
}
class GoldenRetriever : Dog
{
public override string Speak()
{
return "I am a golden retriever who says "
+ base.Speak();
}
}
Теперь класс Dog
объявил Speak
равным virtual
, что позволяет производным классам предоставлять дополнительную или новую реализацию.Это не нарушает контракт с IAnimal
, так как любой вызов метода Speak
по-прежнему возвращает строку.
Хорошо, последний пример.Помните, что интерфейсы не требуют реализации - они только требуют выполнения контракта.Это означает, что интерфейс заботится только о том, чтобы в реализующем классе существовал член с соответствующей подписью.Это означает, что мы могли бы также сделать это:
interface IAnimal
{
string Speak();
}
abstract class Dog : IAnimal
{
public abstract string Speak();
}
class GoldenRetriever : Dog
{
public override string Speak()
{
return "I am a golden retriever";
}
}
Обратите внимание, что класс Dog
вообще не обеспечивает реализацию для Speak
, но удовлетворяет требованиям контракта.
Интерфейсы также наследуются от класса к классу, поэтому во всех приведенных выше примерах и Dog
, и GoldenRetriever
реализуют интерфейс IAnimal
.Ни один из классов не скрывает метод Speak
- оба класса реализуют это.
Хорошо, я думаю, что ваша путаница может быть связана с тем фактом, что виртуальныйМетод определяется в интерфейсе, а не в классе.Вот IL для интерфейса, который я определил выше:
.class private interface abstract auto ansi IAnimal
{
.method public hidebysig newslot abstract
virtual instance string Speak() cil managed
{
}
}
Хотя вы и правы, что метод определен как virtual
, вы также должны заметить, что тип здесь обозначен как interface
.Это просто детали реализации MSIL, сгенерированного компилятором Microsoft C # - другой компилятор может легко генерировать другой код, если семантически он обеспечивает тот же результат.
Здесь важно следующее: даже если методобъявлен как virtual
в интерфейсе, что не означает, что это то же самое, что и метод virtual
, объявленный в классе.