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
?
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>
.
In Java, I would use wildcards in restriction of ITask
generic types, in Kotlin, the above approach would have worked.
But how to solve it using C#?
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>
.
Addendum: having TQuestion
be IQuestion<object>
is only a problem because IQuestion
doesn't have variance defined (so, it is invariant by default). If you define as I show below, you can useIQuestion<object>
(the same goes for 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; }
}
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.
interface ITask<T>
{
IQuestion<T> Question { get; }
List<IAnswer<T>> Answers { get; }
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With