关于c#:为什么在实现接口方法时允许虚拟化?

why virtual is allowed while implementing the interface methods?

我有一个带有接口的特定查询。默认情况下,接口方法是抽象的和虚拟的,因此如果我们在类中实现该接口并给出定义,我们实际上会重写该方法,但是当我们在实现类中再次将该方法标记为虚拟的时候,为什么编译器没有考虑到我们实际上正试图隐藏原始的接口虚拟方法。就像在基类和派生类中有一个虚拟方法,在这种情况下,编译器会警告您正在隐藏基类方法,因此如果有意隐藏基类方法,请使用new。

1
2
3
4
5
6
7
8
9
10
11
12
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


默认情况下,从接口实现的方法不是虚拟的。您只是提供接口定义中定义的契约的实现。通过将方法标记为virtual,您可以允许派生类提供附加的或单独的实现,同时仍然按照定义履行合同。

考虑这个例子:

1
2
3
4
5
6
7
8
9
10
11
12
interface IAnimal
{
    string Speak();
}

class Dog : IAnimal
{
    public string Speak()
    {
        return"Bark!";
    }
}

Dog类通过提供合同IAnimal的实现来实现接口。这里没有虚拟方法,也没有重写。

现在考虑这个例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
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类已经声明Speakvirtual,允许派生类提供附加的或新的实现。这不会破坏与IAnimal的约定,因为对Speak方法的任何调用仍然返回字符串。

好,最后一个例子。记住,接口不需要实现——它们只需要满足契约。这意味着接口只关心具有匹配签名的实现类中是否存在成员。这意味着我们也可以这样做:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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的实现,但已经满足了合同的要求。

接口也从一个类继承到另一个类,因此在上面的所有示例中,DogGoldenRetriever都实现了IAnimal接口。两个类都不隐藏Speak方法——这两个类都实现了它。

好吧,我认为您的困惑可能来自这样一个事实:虚拟方法是在接口中定义的,而不是类。下面是我在上面定义的接口的IL:

1
2
3
4
5
6
7
.class private interface abstract auto ansi IAnimal
{
    .method public hidebysig newslot abstract
        virtual instance string Speak() cil managed
    {
    }
}

虽然您正确地将方法定义为virtual,但您还需要注意,这里的类型被指定为interface。这纯粹是微软C编译器生成的MSIL的一个实现细节——只要在语义上提供相同的结果,另一个编译器就可以轻松地生成不同的代码。

这里重要的是:尽管方法在接口中声明为virtual,但这并不意味着它与类中声明的virtual方法相同。


接口不是基类,因此实现方法不被重写。接口只声明方法,默认情况下接口方法不是虚拟的,而事实接口只声明实现该接口的类上可用的方法。

声明不能是虚拟的。

实现可以是或不能是完全依赖于实现者逻辑的虚拟实现。