2017-02-23 67 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; } 
}