почему виртуальный допускается при реализации методов интерфейса? - PullRequest
13 голосов
/ 17 декабря 2010

У меня есть один конкретный запрос с интерфейсами.По умолчанию методы интерфейса являются абстрактными и виртуальными, поэтому, если мы реализуем этот интерфейс и даем определение в классе, мы фактически переопределяем этот метод, но когда мы снова помечаем метод как виртуальный в классе реализации, почему компилятор не считает, что мы на самом деле пытаемсяскрыть оригинальный интерфейсный виртуальный метод. Например, если у нас есть виртуальный метод в базовом классе, а производный класс снова помечает метод как виртуальный, в этом случае компилятор выдает предупреждение о том, что вы скрываете метод базового класса, поэтому используйте new, если вы намеренноскрытие метода базового класса.

public interface ITestInterface
{
 void virtualmethod(); // this method is by default virtual. 
}

public class TestInterface :ITestInterface
{
 public virtual void virtualmethod()
 {
// Now compiler should consider that i am actually hiding the interface virtual method.
 }
}

если вы построите приведенный выше код для интерфейса и откроете в ILDASM, вы увидите такой код: .method public hidebysig newslot abstract virtual instance void virtualmethod() cil managed { }//end of method ITestInterface::virtualmethod

Ответы [ 2 ]

45 голосов
/ 17 декабря 2010

Методы, которые реализованы из интерфейса, не виртуальные по умолчанию.Вы просто предоставляете реализацию контракта, определенного в определении интерфейса.Помечая метод как 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, объявленный в классе.

3 голосов
/ 17 декабря 2010

Интерфейс не является базовым классом, поэтому методы реализации не переопределяются. Интерфейс только объявляет методы, Методы интерфейса не являются виртуальными по умолчанию, а на интерфейсах-фактиках объявляются только методы, доступные в классе, который реализует этот интерфейс.

Объявление не может быть виртуальным.

Реализация может быть или не быть виртуальной, которая полностью зависит от логики разработчика.

...