【问题标题】:Set inner object's member as outer object using the object initialization syntax in C#使用 C# 中的对象初始化语法将内部对象的成员设置为外部对象
【发布时间】:2021-07-03 23:24:27
【问题描述】:

上下文

  • 我有一个List<T> 类型为Question
  • Question 类又包含一个List<Answer>
  • Answer 类有一个名为 public Question Question { get; set; } 的成员,其中存储了答案所针对的问题。

我正在使用集合初始化语法将Question 项添加到列表和对象初始化以创建新的Question。在这样做的同时,我还使用对象初始化语法(嵌套)创建了新的 Answer 对象。


问题

如何将内部Answer 类的Question 成员设置为引用封闭的Question 对象?我知道创建Answer 的时间点,Question 甚至没有完全初始化。但是有什么方法可以获取外部Question 实例,以便我可以将其设置为内部Answer


代码

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

【问题讨论】:

  • 为什么需要这样做?它创建了一个冗余的数据结构,将来可能会导致错误。计算父节点比存储它更好。

标签: c# this object-initializers collection-initializer


【解决方案1】:

这是不可能的。但是您可以在创建所有答案后将问题设置为所有答案。在使用集合初始化期间,不要为 question 属性赋值。在您的构造函数中,您执行以下操作:

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

【讨论】:

    【解决方案2】:

    您不能在集合/对象初始化程序中执行此操作,但我认为您一开始不应该在此处执行此操作。手写每个答案对应的问题是很容易出错的。有时您可能也会忘记这样做。

    我建议您为Question 中的Answers 属性添加一个自定义设置器,该设置器还设置答案的Question 属性:

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

    然后在对象初始化器中,初始化答案列表,而不是仅仅添加:

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

    这会编译为:

    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;
    

    如您所见,setter 被调用,并且答案的Question 属性将被设置。

    【讨论】:

    • 好方法!当新问题添加到列表中时,甚至可以使用IList 的自定义实现来设置Question 属性。
    • @SomeBody 是的,如果你这样做,你就不再需要 new List&lt;Answer&gt; 了(假设 Answers 在构造函数中被初始化),但是 IMO 只是为此制定了一个自定义列表实现有点矫枉过正:-)
    • 这正是我所需要的!非常感谢:)
    • @SomeBody 听起来也不错。我实际上有QuestionAnswer 的子类,所以我认为自定义class AnswerList : IList&lt;Answer&gt; 也可以足够合理地创建。但现在,我将采用@Sweeper 的方法。谢谢:)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-07-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-06-21
    • 1970-01-01
    • 2010-09-27
    相关资源
    最近更新 更多