2010-12-17 88 views
11

我有一个具体的查询与接口。默认情况下,接口方法是抽象的和虚拟的,所以如果我们实现该接口并在类中定义,我们实际上会覆盖该方法,但是当我们在实现类中再次将该方法标记为虚拟时,为什么编译器不考虑我们实际上正在尝试隐藏原始接口的虚拟方法。就像我们在基类中有一个虚拟方法并且派生类再次将方法标记为虚拟的那样,编译器会给出警告,说明您隐藏了基类方法,所以如果您故意使用新方法隐藏基类方法。为什么在实现接口方法时允许虚拟?

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

而不是虚拟的,假设接口中的方法默认是抽象的,更有意义。 – 2010-12-17 12:44:41

+0

是的,这很好,但一旦编译器附加虚拟方法,并且你在实现该方法时再次虚拟,那么编译器应该说你隐藏了原始声明。 – 2010-12-17 12:54:49

回答

39

方法是虚拟默认。您只是提供了在接口定义中定义的合同的实现。通过将方法标记为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类已宣布Speakvirtual这允许派生类,以提供额外的或新的实现。这并不违反与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没有实现还满足了合同的要求。

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


好吧,我想你的困惑可以从虚拟方法是在一个接口,而不是一个类中定义的事实到来。下面是我的界面上面定义的IL:

.class private interface abstract auto ansi IAnimal 
{ 
    .method public hidebysig newslot abstract 
     virtual instance string Speak() cil managed 
    { 
    } 
} 

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

这里重要的是这样的:尽管该方法在界面中声明为virtual并不意味着它与在类中声明的virtual方法是一样的。

+0

请再次检查问题,因为我添加了相同的IL代码 – 2010-12-17 12:56:45

+0

.method public hidebysig newslot抽象虚拟实例void virtualmethod()cil managed {} //方法结束ITestInterface :: virtualmethod – 2010-12-17 13:03:13

2

接口不是基类,所以实现方法没有被覆盖。接口只声明方法,接口方法默认是非虚拟的,事实上接口只声明实现该接口的类上可用的方法。

声明不能是虚拟的。

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

+0

接口只是一个虚拟类型方法,所以行为应该与类相同。 – 2010-12-17 12:59:09

+1

@Mohit - 这不完全正确。是的,他们只是另一种类型,但他们是*界面*类型,使所有的差异。 IL级别的接口和类是不同的。 – 2010-12-17 14:18:23

相关问题