2017-02-23 14 views
8

テスト用のシステムを作成するとします。テストにはタスクのリストが含まれ、各タスクには質問と回答のリストが含まれます。また、質問や回答はテキストだけでなく、イメージなどとすることもできます。だから我々は、ジェネリックを使用します。汎用インターフェースまたはクラスでのwhere制約の使用

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; } 
} 

TQuestionIQuestionTAnswerのサブタイプでなければならないことを書くためにどのように - 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> 

Becouse、実際には、IQuestion<string>はしないでくださいIQuestion<object>から継承されます。

Javaの では、私はKotlinでは、上記のアプローチは、働いているだろう、ITaskジェネリック型の制約にワイルドカードを使用します。

しかし、どのようにC#を使用して解決するには?

答えて

4

あなたは三番目のパラメータが必要です。ご存知のように

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

を、IQuestion<string>IQuestion<object>から継承されていないが、この方法は、あなたがIQuestion<string>ことTQuestion持つことができます。


補遺:TQuestionIQuestion<object>ことがあるが、IQuestionvarianceが定義されていないので、唯一の問題である(そう、それはデフォルトでは不変です)。以下に示すように定義した場合、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#」のジェネリックの差異を深く(btw、読んでおく必要がある)と明示的に言わなければならない理由を説明しました。要するに、実行時に型の不一致を避けるためです。この回答も参照できます: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が望んでいるものに戻ってしまいます。たとえば、この場合の分散を使用すると、第3のパラメータ(Javaと同じように)よりも制限が少なくなります.Codorの解決策は途中です。そしてリンクに感謝します。 – Theraot

+0

それだけです!分散を使用して、私は最初に必要だったものを得ました: 'class TextTask:ITask '。 – Letfar

4

私は質問を理解しているので、タイプパラメータTQuestionTAnswerを前に使用しないで、ITaskに追加のタイプパラメータを導入することによって制約を定式化することができます。

interface ITask<T> 
{ 
    IQuestion<T> Question { get; } 
    List<IAnswer<T>> Answers { get; } 
} 
関連する問題