2010-12-17 85 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

相關問題