Zannith Zannith - 1 month ago 4
C# Question

how do i call a subclass method on a superclass list containing subclasses

I had a hard time wording my title so let me try to elaborate now. First here is my relevant code :

class Question
{
static bool checkFile(XElement q)
{
foreach (XElement a in q.Descendants())
{
if (a.Name.LocalName == "file")
{
return true;
}
}
return false;
}
protected string questionText;
protected List<File> files;
protected Question question;
public Question(XElement q)
{
questionText = q.Element("questiontext").Element("text").Value.ToString();
string name = q.Attribute("type").Value.ToString();
if (checkFile(q))
files.Add(new File(q));
}
}
class multichoice : Question
{
private List<string> answers;
public multichoice(XElement q)
: base(q)
{
foreach (XElement a in q.Elements())
{
if (a.Name.LocalName == "answer")
answers.Add(a.Element("text").Value.ToString());
}
}
public void writeQuestion(HtmlTextWriter writer)
{
writer.RenderBeginTag("p");
writer.Write("<strong>Multiple Choice: </strong>" + this.questionText);
writer.RenderEndTag();
writer.AddAttribute("type", "A");
writer.RenderBeginTag("ol");
foreach (string answer in answers)
{
writer.RenderBeginTag("li");
writer.Write(answer);
writer.RenderEndTag();
}
writer.RenderEndTag();
}
}
class truefalse : Question
{
public truefalse(XElement q)
: base(q)
{

}
public void writeQuestion(HtmlTextWriter writer)
{
writer.RenderBeginTag("strong");
writer.Write("True or False : ");
writer.RenderEndTag();
writer.Write(questionText);
}
}


So I am creating multiple types of questions all being subclasses of "Question". Question contains all data that applies to every type of question and these subclasses contain methods unique to them, the main one being "writeQuestion".
Now what I am trying to do with it is something like this:

static List<Question> collectQuestions(XDocument doc)
{
XDocument xdoc = doc;
string elementName = null;
List<Question> questions = null;
foreach (XElement q in xdoc.Descendants("question"))
{
elementName = q.Attribute("type").Value.ToString();
if (elementName != "category")
continue;
if (elementName == "truefalse")
questions.Add(new truefalse(q)); //writeTrueFalse(writer, q);
else if (elementName == "calculatedmulti")
questions.Add(new calculatedmulti(q)); // writeCalculatedMulti(writer, q);
else if (elementName == "calculatedsimple")
questions.Add(new calculatedsimple(q)); // writeCalculatedSimple(writer, q);
else if (elementName == "ddwtos")
questions.Add(new Draganddrop(q)); //writeDragAndDrop(writer, q);
else if (elementName == "description")
questions.Add(new Description(q)); // writeDescription(writer, q);
else if (elementName == "essay")
questions.Add(new Essay(q)); // writeEssay(writer, q);
else if (elementName == "gapselect")
questions.Add(new Gapselect(q)); // writeGapSelect(writer, q);
else if (elementName == "matching")
questions.Add(new Matching(q)); // writeMatching(writer, q);
else if (elementName == "multichoice")
questions.Add(new multichoice(q)); // writeMultipleChoice(writer, q);
else if (elementName == "multichoiceset")
questions.Add(new Allornothing(q)); // writeAllOrNothing(writer, q);
else if (elementName == "numerical")
questions.Add(new Numerical(q)); // writeNumerical(writer, q);
else if (elementName == "shortanswer")
questions.Add(new shortanswer(q)); // writeShortAnswer(writer, q);
else
continue;
}
return questions;
}
questions = collectQuestions(someDocument);
foreach (Question question in questions)
{
question.writeQuestion(writer);
}


Is there a way to call the writeQuestion on each of the items? right now it of course gives the error that Questions does not contain a definition for writeQuestion even though each of its subclasses does. Please comment if i should add anything more for clarification, my code has gotten a little mangled as i have been repeatedly reworking it. I am decently new to working with classes like this so i may be missing some key concepts, please point out anything you see, thankyou.

Answer

Make the base class abstract, add an abstract WriteQuestion member to the base class, and then override it in each concrete implementation.