【问题标题】:C# - why am I getting an empty collection?C# - 为什么我得到一个空集合?
【发布时间】:2016-12-16 00:40:01
【问题描述】:

为什么只有我在子类中覆盖 people 集合才有项目?这是代码。如果我取消注释被覆盖的方法,那么我的集合中有 2 个人在公园里。

public class Park : Thing
{
}

public abstract class Thing
{
    public virtual List<Thing> people { get; } = new List<Thing>();
}

public class PersonA : Thing
{
    Thing p;
    public string Name { get; set; }
    public PersonA(Thing p)
    {
        this.p = p;
        Name = "Marry";
        this.p.people.Add(this);
    }
    //public override List<Thing> people => p.people;
}

public class PersonB : Thing
{
    Thing p;
    public string Name { get; set; }
    public PersonB(Thing p)
    {
        this.p = p;
        Name = "Joe";
        this.p.people.Add(this);
    }
    //public override List<Thing> people => p.people;
}

这是测试应用程序:

Thing park = new Park();
park = new PersonA(park);
park = new PersonB(park);

Console.WriteLine(park.people.Count);

【问题讨论】:

  • 使用调试器并单步调试代码,您会发现哪里出错了。你有没有试过..?
  • 您的基类有一个新列表。因此,除非您覆盖它,否则它将为空。尝试调试。
  • 在构造函数中,您将添加到成员p 的列表中,而不是类自己的列表中。 p.peoplethis.people 不是同一个列表。除非你试图表达一个人有一个的东西,它不应该需要p成员。
  • @Uueerdo 哦,就是这样,有道理。谢谢。

标签: c# decorator


【解决方案1】:
Thing park = new Park();

在这里,您将实例化一个Park 对象并将其分配给一个类型为Thing 的变量。到目前为止,一切顺利。

park = new PersonA(park);

这里您正在实例化一个PersonA,并且因为您将Park 对象传递给构造函数,所以构造函数将自身添加到ParkPeople 集合中。因此,该集合现在包含一个人。再说一次,到目前为止,一切都很好。

但是,您随后将新的 PersonA 对象分配给 park 变量。这不是运行时错误,因为变量的类型为Thing,而PersonAThing,但这几乎可以肯定是您的逻辑错误,因为我想不出您想要的原因一个名为 park 的变量,它指向一个人。

关键在于,此时park.People 不指代Park 对象的人员集合;它指的是PersonA 对象的人员集合,它是空的。

park = new PersonB(park);

现在,当您调用 PersonB 构造函数时,您不会将 Park 对象传递给它;您将分配给park 变量的PersonA 对象传递给它。所以PersonB 构造函数将自己添加到PersonAPeople 集合中,该集合现在包含一个人。

但同样,您将结果分配给park。所以现在park 包含一个PersonB 对象,其People 集合为空。这就是为什么:

Console.WriteLine(park.people.Count);

打印零。

【讨论】:

  • 帮助完成,谢谢。关于您的第二段,这就是装饰器模式的工作原理。您将装饰器添加到组件。一开始它看起来有点奇怪,但总的来说它是有意义的并且是一个非常有用的模式。这个例子是我在一个更大的应用程序中遇到的一个简化问题。
  • @haosmark 但是,这似乎仍然是您问题的根源。我对装饰器设计模式了解不多,但我肯定知道分配东西是你的代码不起作用的原因:)
  • @Francis Lord 不,代码不起作用,因为 Person 正在返回它自己的集合,而不是父母的集合。这就是取消注释 p.people 解决问题的原因。
  • @haosmark,明白了。我对这种模式很熟悉,而且我确信您原始代码中的用法是明智的。只是通常装饰器的应用程序会产生相同的“类型”对象,只是具有附加或修改的行为。因此,也许装饰一个普通的金融计算器会产生一个应用拖欠费用或其他东西的计算器。我只是觉得公园“变成”一个人是非常令人困惑的。
  • @Joe Farrell 好吧,我是模式的新手,但据我了解,这可以分解为组件、具体组件、装饰器和具体装饰器。在上面的例子中,Park 是一个具体的组件,Persons 是具体的装饰器,Thing 是一个组件。我想我可以创建一个 ThingDecorator 并让 Persons 从中扩展,以使其在视觉上更具逻辑性,但我认为它是多余的并且没有。我不知道这是否是非正统的,但在我没有经验的头脑中,它很适合。该应用程序本身就是一个计算器,它用劳动力和设备来装饰服务。