简体   繁体   English

使用带有通用接口或类的约束

[英]Using where constraints with generic interface or class

Suppose we write a system for tests. 假设我们编写了一个测试系统。 Test contains the list of tasks and each task contains question and the list of answers. 测试包含任务列表,每个任务包含问题和答案列表。 Also we assume that question or answer can be not only the text, but image for example. 我们还假设问题或答案不仅可以是文本,还可以是图像。 So we use generics: 所以我们使用泛型:

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

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

And the problem occurs when we creating the Task: 当我们创建任务时会出现问题:

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

How to write that TQuestion should be subtype of IQuestion and TAnswer - subtype of IAnswer ? 如何写TQuestion应该是IQuestionTAnswer子类型 - IAnswer子类型?

I've tryed: 我试过了:

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

But when I created: 但是当我创建时:

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

This did not work: 这不起作用:

class TextTask : ITask<TextQuestion, TextAnswer>

Becouse, in fact, IQuestion<string> don't inherited from IQuestion<object> . 事实上, IQuestion<string>不是从IQuestion<object>继承的。

In Java , I would use wildcards in restriction of ITask generic types, in Kotlin , the above approach would have worked. Java中 ,我会在限制ITask泛型类型时使用通配符,在Kotlin中 ,上述方法ITask

But how to solve it using C#? 但是如何使用C#解决它?

In the way I understand the question, you can formulate the constraint by introduction of an additional type parameter in ITask as follows, omitting the type parameters TQuestion and TAnswer used before. 在我理解这个问题的方式中,你可以通过在ITask引入一个额外的类型参数来制定约束,如下所示,省略之前使用的类型参数TQuestionTAnswer

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

You need a third parameter: 你需要第三个参数:

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

As you know, IQuestion<string> don't inherited from IQuestion<object> , but this way you can have TQuestion be IQuestion<string> . 如您所知, IQuestion<string>不是从IQuestion<object>继承的,但是这样您就可以将TQuestion设为IQuestion<string>


Addendum: having TQuestion be IQuestion<object> is only a problem because IQuestion doesn't have variance defined (so, it is invariant by default). 附录:将TQuestion设为IQuestion<object>只是一个问题,因为IQuestion没有定义方差 (因此,默认情况下它是不变的)。 If you define as I show below, you can use IQuestion<object> (the same goes for IAnswer ). 如果你定义如下所示,你可以使用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; }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM