2013-03-11 55 views
1

我遇到了一些代碼,我不太清楚它爲什麼可以工作,或者你爲什麼想這樣做。我會喜歡它,如果有人能爲我撕下它。我很瞭解OOP的概念,我之前從未見過這種技術。由於接口和抽象類保護級別方法

這裏是例子:如果你在談論這行代碼

public interface IInterface 
{ 
    IEnumerable<object> DoSomething(); 
} 

public abstract class MyBase : IInterface 
{ 
    protected MyBase() 
    { 
    } 

    IEnumerable<object> IInterface.DoSomething() 
    { 
     return DoSomething(); 
    } 

    protected virtual IEnumerable<object> DoSomething() 
    { 
     return new List<object>(); 
    } 
} 

public class MyClass : MyBase 
{ 
    internal MyClass() : base() {} 

    protected override IEnumerable<object> DoSomething() 
    { 
      return new List<object>(); 
    } 
} 
+1

目前還不清楚你對哪個方面感到困惑。 – 2013-03-11 16:04:16

+0

我猜測它是受保護隱式實現的顯式接口實現(如果這就是它 - 我會說隱式接口實現是公共的)。 – 2013-03-11 16:07:26

+0

我的歉意。混淆我的部分是我看作是IInterface.DoSomething返回虛擬DoSomething的私有實現的東西。我也注意到了IInterface。它是編譯所必需的。 – Kirby 2013-03-11 16:10:13

回答

1

IEnumerable<object> IInterface.DoSomething() 

這就是所謂的explicit interface implementation

這迫使消費者只能通過接口 訪問此方法,而不是直接訪問您的類。

上述方法不是私有的,它只是沒有明確地在代碼中公開設置。事實上,使用顯式接口實現,甚至不能使用訪問修飾符。

採取這種方法的原因之一是強制更好的編碼實踐。如果你是這個類的開發者,並且你知道它只能通過一個接口來訪問,那麼這就是迫使它發生的方法。

+0

我知道顯式接口imp,並且我知道它在使用多個碰巧具有相同命名方法的接口時派上用場。我仍然不確定程序員爲什麼這樣做,以及它給了什麼好處。 – Kirby 2013-03-11 16:19:09

+1

這不僅僅是在有兩個定義時使用一個接口;它是強迫類通過接口而不是直接使用類本身(即使只涉及一個接口)。我的答案顯示了爲什麼要這樣做的一個原因。 – 2013-03-11 16:21:37

+0

在C#中,你不能修改顯式的接口實現 - 它總是私有的。在VB.NET中,我相信你可以明確地實現你想要的任何訪問。就我個人而言,我更喜歡C#的方式。 – 2013-03-11 16:26:09

0

把我的頭我有這個實際使用的思維麻煩的頂部,但有一兩件事,這完成是MyBase類型的對象或它的子類沒有publicinternal LY可見DoSomething()方法:

MyClass a = new MyClass(); 
a.DoSomething(); // Compile error 

但是當對象被用作IInterfaceDoSomething()方法是可見的:

void AMethod(IInterface i) 
{ 
    i.DoSomething(); // compiles just fine 
} 

void AnotherMethod(MyBase a) 
{ 
    AMethod(a); // as does this 
} 

使0非顯式版本允許子類覆蓋DoSomething()方法的行爲。

這是一種實現方法,在使用MyBase s作爲MyBase s時不能直接調用,但可以在被視爲IInterfaces時使用。沒有什麼可以阻止某人這樣做:((IInterface)a).DoSomething();但它似乎隱藏是由於語義原因。

+0

有關使用的更多信息,在創建並返回MyClass的相同程序集中有一個工廠類。使用該MyClass的類也在同一個程序集中,它調用方法不存在的問題。示例var myClass = SomeFactory.GetMyClass(); myClass.DoSomething() – Kirby 2013-03-11 16:17:26

+0

帶有該代碼的類是否繼承自「MyBase」? – JLRishe 2013-03-11 16:19:36

+0

這可能是因爲'GetMyClass()'返回一個接口,而不是具體的myBase或myClass。 – 2013-03-11 16:20:07

0

我認爲這是它所實現的模板模式here。通常您會看到與strategy模式一起使用的模板模式。在您的具體示例中,IInterface的用戶可以調用方法,而不考慮具體子類如何實現該方法。

這種OO編程允許您利用其他一些模式,例如AbstractFactory創建MyBase的具體子類,它們實現IInterface

0

重要的是要注意的是,兩個DoSomething方法沒有任何關係 - 他們只是碰巧有相同的名字。

基本上,你剛剛有一個正常的界面,公開了一個DoSomething方法,因此具有IInterface對象的調用者可以調用它。然後,它將依次將該呼叫傳遞給受保護的DoSomething方法的適當實現,該方法可以來自基類或派生類。

明確實現這樣迫使你的合同,而不是實施代碼 - 並沒有真正提供任何實際保護,只是使它在聲明你的變量更難意外地使用了錯誤的類型。他們很容易可以做:

public abstract class MyBase : IInterface { 
    public virtual IEnumerable<object> DoSomething() { 
     // blah 
    } 
} 

public class MyClass : MyBase { 
    public override IEnumerable<object> DoSomething() { 
     // blah 
    } 
} 

,但它可以讓你在聲明爲MyClassMyBase,你可能不希望他們做一個變量調用DoSomething

+0

這個解釋讓我對事情變得更加清楚。你是否也同意nattyddubbs這看起來像模板模式?我將需要對這種模式進行一些閱讀。 – Kirby 2013-03-11 16:32:27

+0

這似乎是正確的 - 以前從來沒有將它稱爲模板模式,但這是非常簡單的基於繼承的OOP - 基類和子類中的重寫方法,以使它們按照您希望的方式運行。 – 2013-03-11 16:47:39

+0

想通過投票給你道具,但我的代表還不夠高。再次感謝您指出命名礦塊! – Kirby 2013-03-11 18:31:32

0

在C#中,明確地使用它什麼都不做的密封的方法實現一個接口,但調用一個受保護的虛擬方法允許派生類關於他們希望與界面做了很大的靈活性;該方法應該給出一個名稱其他比接口方法的名稱(在上面的例子中,它可能是DoSomething_Prot)。顯式接口實現使得派生類重新實現不可能鏈接到基類實現,但是如果基類實現正在做的唯一事情是鏈接到受保護的虛擬或抽象方法,則不需要派生類類來重新實現接口。此外,即使派生類要故意地或作爲協方差的結果重新實現接口,它仍然能夠使用基類中的受保護方法調用基類實現的「膽量」。

把所有的代碼,其中隱式地實現接口是不是把代碼中的顯式實現更好,因爲衍生類代碼可以通常是鏈到私有成員公共虛擬方法的接口實現。然而,這種方法要求所有派生類公開實施具有相同簽名的方法。雖然看起來好像人們自然會期望的那樣,但並不總是如此。例如,在上面的例子中派生類可能希望有其DoSomething方法返回比IEnumerable<object>以外的類型(例如它可能返回IList<Kangaroo>)。實現interfae的方法仍然必須返回精確的類型IList<Kangaroo>,但是知道它的代碼是處理派生類型的,可以使用返回類型作爲IList<Kangaroo>而不使用類型轉換。如果該方法的實際代碼放在一個稱爲DoSomething_Prot()方法,派生類都可以重寫DoSomething_Prot並聲明new public IList<Kangaroo> DoSomething()。如果基類方法被稱爲DoSomething(),那麼派生類就不可能覆蓋它並定義一個具有不同返回類型的新方法。