使用通用接口或类的约束
假设我们写一个测试系统。 测试包含任务列表,每个任务包含问题和答案列表。 我们也假定问题或答案不仅可以是文本,而是可以是例如图像。 所以我们使用泛型:
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
应该是IQuestion
和TAnswer
子类型 – IAnswer
子类型?
我试过了:
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>
事实上,事实上, IQuestion<string>
不会从IQuestion<object>
继承。
在Java中 ,我将使用通配符限制ITask
泛型类型,在Kotlin中 ,上述方法将起作用。
但如何解决它使用C#?
你需要第三个参数:
interface ITask<TQuestion, TAnswer, T> where TQuestion : IQuestion<T> where TAnswer : IAnswer<T>
如您所知, IQuestion<string>
不会从IQuestion<object>
继承,但这样您可以使用IQuestion<string>
作为IQuestion<string>
。
附录:因为IQuestion
没有定义差异 (所以默认情况下是不变的),所以只有IQuestion<object>
才是问题。 如果你如下所示定义,你可以使用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; } }
在理解这个问题的方式中,可以通过在ITask
引入一个附加的类型参数来形成约束,如下所示,省略之前使用的类型参数TQuestion
和TAnswer
。
interface ITask<T> { IQuestion<T> Question { get; } List<IAnswer<T>> Answers { get; } }