2017-02-23 66 views
8

假設我們編寫一個測試系統。測試包含任務列表,每個任務包含問題和答案列表。我們還假定問題或答案不僅可以是文本,而可以是例如圖像。因此,我們使用泛型:使用通用接口或類的約束條件

public interface IQuestion<T> 
{ 
    T Content { get; } 
} 

public interface IAnswer<T> 
{ 
    T Content { get; } 
    bool IsCorrect { get; } 
} 

當我們創建任務時出現問題:

interface ITask<TQuestion, TAnswer> 
{ 
    TQuestion Question { get; } 
    List<TAnswer> Answers { get; } 
} 

如何編寫TQuestion應該是IQuestionTAnswer亞型 - 的IAnswer亞型?

我tryed:

interface ITask<TQuestion, TAnswer> 
    where TQuestion : IQuestion<object> 
    where TAnswer : IAnswer<object> 

但我創建的時候:

class TextQuestion : IQuestion<string> {...} 
class TextAnswer : IAnswer<string> {...} 

這不起作用:

class TextTask : ITask<TextQuestion, TextAnswer> 

Becouse,其實IQuestion<string>不從IQuestion<object>繼承。

的Java,我會用通配符ITask泛型類型的限制,在科特林,上述方法會奏效。

但如何解決它使用C#?

回答

4

您需要第三個參數:

interface ITask<TQuestion, TAnswer, T> 
    where TQuestion : IQuestion<T> 
    where TAnswer : IAnswer<T> 

如你所知,IQuestion<string>不從IQuestion<object>繼承,但這樣一來,你可以有TQuestionIQuestion<string>


附錄:具有TQuestionIQuestion<object>只是因爲IQuestion沒有variance限定的問題(因此,它是由默認不變)。如果您按照以下所示定義,則可以使用IQuestion<object>IAnswer也是如此)。

public interface IQuestion<out T> 
{ 
    T Content { get; } 
} 

public interface IAnswer<out T> 
{ 
    T Content { get; } 
    bool IsCorrect { get; } 
} 

interface ITask<TQuestion, TAnswer> 
    where TQuestion : IQuestion<object> 
    where TAnswer : IAnswer<object> 
{ 
    TQuestion Question { get; } 
    List<TAnswer> Answers { get; } 
} 
+1

有趣的答案; Jon Skeet解釋了爲什麼你必須明確地說他想在他的書C#中深入挖掘泛型(順便說一句,這是必讀)。總之,這是爲了避免執行時類型不匹配。你也可以看到這個答案:http://stackoverflow.com/a/246101/574059和Eric Lippert撰寫的這篇文章:https://blogs.msdn.microsoft.com/ericlippert/2007/10/16/covariance-and -contravariance-in-c-part-one/ – gobes

+0

@gobes我知道背後的原因。這回落到OP想要的東西上,例如在這種情況下使用方差將比使用第三個參數更少限制(更類似於Java所做的),Codor的解決方案位於中間某處。並感謝您的鏈接。 – Theraot

+0

就是這樣!使用方差,我得到了我最初想要的:'class TextTask:ITask '。 – Letfar

4

以我理解問題的方式,您可以通過在ITask中引入附加類型參數來制定約束,如下所示,省略之前使用的類型參數TQuestionTAnswer

interface ITask<T> 
{ 
    IQuestion<T> Question { get; } 
    List<IAnswer<T>> Answers { get; } 
}