1

Context

  • I have a List<T> of type Question.
  • Class Question, in turn, contains a List<Answer>.
  • Class Answer has a member called public Question Question { get; set; } which stores the question of which the answer is for.

I'm using the collection initialization syntax to add a Question item to the list and object initialization to create a new Question. While doing so, I'm also creating new Answer objects using the object initialization syntax(nested).


Problem

How do I set the Question member of the inner Answer class to refer to the enclosing Question object? I know the point at which an Answer is created, the Question is not even fully initialized. But is there any way to obtain the outer Question instance so that I can set it to the inner Answer.


Code

private List<Question> questions = new()
{
    new Question 
    { 
            Id = 1, 
            Text = "Test Question 1", 
            Difficulty = QuestionDifficulty.Easy, 
            Answers = 
            {
                new Answer { Id = 1, Question = [?] },
                new Answer { Id = 2, Question = [?] }   // What should replace [?] here?
            }
    } 
};
1
  • 1
    Why do you need to do this? It creates a redundant data structure that can lead to bugs in the future. It's better to compute the parent than to store it. Commented Apr 8, 2021 at 6:44

2 Answers 2

2

You can't do it in the collection/object initialiser, but I'd argue that you shouldn't do it there in the first place. It's quite error-prone to handwrite what the corresponding question for each answer should be. You might forget to do that sometimes too.

I suggest that you add a custom setter for the Answers property in Question that also sets the answer's Question property:

private List<Answer> answers;
public List<Answer> Answers {
    get => answers;
    set {
        // If you feel like it, you can also set the old answers' questions to null

        answers = value;
        foreach (var answer in answers) {
            answer.Question = this;
        }
    }
}

Then in the object initialiser, initialise the answers' list, rather than just adding to it:

private List<Question> questions = new()
{
    new Question 
    { 
            Id = 1, 
            Text = "Test Question 1", 
            Difficulty = QuestionDifficulty.Easy, 
            Answers = new List<Answer> // <--- here! 
            {
                new Answer { Id = 1 },
                new Answer { Id = 2 }
            }
    } 
};

This compiles to something like:

var question = new Question();
...
var list = new List<Answer>();
var answer1 = new Answer();
answer1.Id = 1;
var answer2 = new Answer();
answer2.Id = 2;
list.Add(answer1);
list.Add(answer2);
question.Answers = list;

As you can see, the setter is called, and the answers' Question property will be set.

Sign up to request clarification or add additional context in comments.

4 Comments

Good approach! Maybe it is even possible to use a custom implementation of IList to set the Question property when a new question is added to the list.
@SomeBody Yeah, if you do that, you don't need new List<Answer> anymore (assuming Answers is initialised in the constructor), but then IMO making a custom list implementation just for this is a bit overkill :-)
This is exactly what I needed! Thanks a lot : )
@SomeBody That sounds good too. I actually have subclasses for both Question and Answer so I think a custom class AnswerList : IList<Answer> can be reasonable enough to create too. But for now, I'll go with @Sweeper's approach. Thanks :)
2

It is not possible. But you can set the question to all answers after you created them. Do not assign a value to the question property during your use of the collection initialization. In your constructor, you do the following:

foreach(var question in questions)
{
    foreach(var answer in question.Answers)
    {
         answer.Question = question;
    }
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.