I’m trying to find a tidy solution to a questionnaire problem. Let us say that I have a Questionnaire class which has a collection of Answers, e.g.
public class Questionnaire
{
public virtual ISet<Answer> Answers {get;set;}
}
Answers need to be of different types depending on the question, e.g. date of birth, marks out of ten, why do you think etc.
My first thought was something like this:
public class Question
{
public virtual QuestionType TypeOfQuestion {get;set;}
public virtual string PromptText {get;set;}
}
public class Answer
{
public virtual Question Question {get;set;}
}
public class DateTimeAnswer : Answer
{
public virtual DateTime Response {get;set;}
}
public class IntegerAnswer : Answer
{
public virtual int Response {get;set;}
}
// etc.
The obvious problem would be that from the questionnaire, there is no access to the Response property:
questionnaire.Answers[0].Response; // compile error
The same would apply to an interface. It would be nicer to use a generic interface, such as:
public interface IAnswer<T>
{
public virtual Question Question {get;set;}
public virtual T Response {get;set;}
}
public class DateTimeAnswer : IAnswer<DateTime> {}
The problem then comes in the Questionnaire class, as the type of IAnswer must be supplied:
public class Questionnaire
{
public virtual ISet<IAnswer<???>> Answers {get;set;}
}
Clearly I don’t want to have many collections of IAnswer each with different types. I could use
ISet<IAnswer<dynamic>>
but then NHibernate wouldn’t like it.
I realise a compromise is needed somewhere, but I’m not sure which is the prettiest. What would you do?
I think subclassing Question as well as answer is a good plan – get rid of that QuestionType enum.
You can then have a MakeAnswer(string) abstract method on Question which encapsulates a lot of logic for you, and can do type conversion etc if necessary.
My solution to the generic problem on Rob’s answer would be something like this:
Where
IAnswerFormatterlooks something like this:And DateTimeAnswer would look like this:
And DateTimeQuestion might look like:
This way your answer can hold the value in their own way, and you NH mappings can specify how it looks in the database (I’d recommend mapping using Discriminators) your Question can be responsible for creating answers from generic responses.