2012-03-20 36 views
2

TL; DR

在接口中隱藏屬性有什麼問題,以便我可以更改其聲明以返回原始屬性的派生類型?在返回派生類型的派生接口中隱藏屬性是可以接受的嗎?

我確定這個問題以前一定要問過,但是我找不到它,並且爲長期問題道歉。

說我有這樣的情況:

public interface A 
{ 
    B TheB{get;} 
} 

public interface MoreSpecificA : A 
{ 
    MoreSpecificB TheMoreSpecificB{get;} 
} 

public interface B{...} 

public interface MoreSpecificB:B{...} 

我想的MoreSpecificA用戶能夠得到的是一個MoreSpecificB的B中。他們可以通過撥打TheB並轉換它,或者他們可以調用方法TheMoreSpecificB。我還可以聲明MoreSpecificA像這樣:

public interface MoreSpecificA : A 
{ 
    new MoreSpecificB TheB{get;} 
} 

所以現在他們可以用同樣的方法,並取回一個MoreSpecificB

使用new隱藏一個方法使我的牙齒處於優勢,所以爲什麼這是一個壞主意?這似乎是一件合理的事情。

在大多數情況下,我所看到的一般建議似乎是使用泛型代替,但這似乎有一個問題,如果我有MoreSpecificA,我想在聲明返回的方法中返回它類型爲A,然後我必須MoreSpecificA延長AMoreSpecificA實例訪問TheB時,因爲它不知道,如果你想A.TheBMoreSpecificA.TheB

public interface ABase<T> where T : B 
{ 
    T TheB{get;} 
} 

public interface A : ABase<B> 
{   
} 

public interface MoreSpecificA : ABase<MoreSpecificB>,A 
{   
} 

public class blah 
{ 
    public A GetA(MoreSpecificA specificA) 
    { 
     return specificA; //can't do this unless MoreSpecificA extends A 
    } 

    public B GetB(MoreSpecificA specificA) 
    { 
     return specificA.TheB; //compiler complains about ambiguity here, if MoreSpcificA extends A 
    } 
} 

這可以通過宣佈一個新的TheB來解決這給歧義MoreSpecificA(但又是新的問題)。

如果MoreSpecificA不在類擴展,則第一種方法blah像現在的MoreSpcificA不能轉換爲A.

上述抱怨雖然寫這篇我注意到,如果我聲明我BaseA到被逆變這樣的:

public interface ABase<out T> where T : B 
{ 
    T TheB{get;} 
} 

和我的課是

public class blah 
{ 
    public ABase<B> GetA(MoreSpecificA specificA) 
    { 
     return specificA; 
    } 

    public B GetB(MoreSpecificA specificA) 
    { 
     return specificA.TheB; //compiler complains about ambiguity here 
    } 
} 

然後我得到兩全其美。此解決方案的適用性取決於A是否向ABase添加了任何內容?

或者是我原來的方案隱藏在派生類型的方法來返回原始方法的派生類型好嗎?

+0

他們的方式,我看到它,你只是遇到了沒有多重繼承創造的限制之一。也許一些工廠或建築模式可以節省一天的時間。 – CodingBarfield 2012-03-20 09:59:00

回答

2

或者是我原來的計劃隱藏在派生類型中的方法來返回原始方法的派生類型好嗎?

只要這意味着完全一樣的東西,我認爲沒關係。你可以在標準庫中看到類似的東西,例如IDbConnection.CreateCommand(返回IDbCommand)和SqlConnection.CreateCommand(返回SqlCommand)。

在這種情況下,它使用IDbConnection版本的顯式接口實現,但它的原理相同。

您也可以在IEnumerator<T>.CurrentIEnumerator.CurrentIEnumerable<T>.GetEnumerator()IEnumerable.GetEnumerator()之間看到。

我只會在更弱類型的方法只是的實現返回調用更強類型方法的結果的情況下使用它,但使用隱式轉換。當他們真的開始做不同的事情時,這很難在後面推論。

+0

謝謝喬恩。在我的情況下,所討論的對象被用作Key。在系統中,所有的鍵都實現了'IKey'和一些更具體的鍵接口,這些接口被用作類型類的鍵的標記。在所有實現類中,它們都有一個具體類型的Key,所有返回IKey(或派生)的接口方法的實現都將返回相同的實例。 – 2012-03-20 08:19:19

+0

@SamHolder:聽起來沒問題。基本上這是彌補.NET中缺乏協變返回類型:( – 2012-03-20 08:23:12