继承与组合不同。当您从 A 继承 B 时,您会说“B 是 A”。在您的情况下,当您从 House 继承 Apartment 时,您说的是“Apartment 是 House”。这显然不是真的,因为公寓不是房子,它是房子的一部分。所以Apartment 不应该继承自House。
属于的关系用组合来表达。您已通过将公寓列表添加到 House(并将 House 属性添加到 Apartment)来做到这一点。
但是,您通常希望保持父列表和子列表的父属性之间的完整性。例如,当您将Apartment 添加到House 时,您希望相应地设置Apartment.House。
使用List<T> 无法完成此行为。实际上List<T> 并不是为了公开这种公共属性,而是为了内部数据存储。出于您的目的,您需要一个System.Collections.ObjectModel.Collection<T>,它允许您进行所需的自定义。
这就是House 和Apartment 之间的关系的工作方式。你需要为Apartment 和Resident 做同样的事情:
public class House
{
public int Number { get; set; }
public string Street { get; set; }
public ApartmentCollection Apartments { get; private set; }
public House() {
Apartments = new ApartmentCollection(this);
}
}
public class Apartment
{
private House house;
public int AptNumber { get; set; }
public int AptRooms { get; set; }
public House House {
get {
return house;
}
set {
house?.Apartments.Remove(this);
house = value;
house?.Apartments.Add(this);
}
}
public List<Resident> Residents = new List<Resident>();
}
public class ApartmentCollection : Collection<Apartment> {
private readonly House parent;
public ApartmentCollection(House parent) {
this.parent = parent;
}
protected override void InsertItem(int index, Apartment item) {
if (item == null) {
throw new ArgumentNullException(nameof(item));
}
if (Contains(item)) {
return;
}
base.InsertItem(index, item);
item.House = parent;
}
protected override void SetItem(int index, Apartment item) {
if (item == null) {
throw new ArgumentNullException(nameof(item));
}
Apartment oldItem = this[index];
if (oldItem.Equals(item)) {
return;
}
int oldIndexOfItem = IndexOf(item);
base.SetItem(index, item);
oldItem.House = null;
item.House = parent;
//If the item was in the collection before, remove it from its old position
if (oldIndexOfItem >= 0) {
base.RemoveItem(oldIndexOfItem);
}
}
protected override void RemoveItem(int index) {
Apartment removedItem = this[index];
base.RemoveItem(index);
removedItem.House = null;
}
protected override void ClearItems() {
Apartment[] removedItems = new Apartment[Count];
CopyTo(removedItems, 0);
base.ClearItems();
foreach(Apartment removedItem in removedItems) {
removedItem.House = null;
}
}
}
现在您可以同时设置Apartment.House 或从House.Apartments 添加和删除项目。另一面总是会自动更新。此外,ApartmentCollection 将防止两次添加相同的公寓或向公寓集合添加 null 值。 List<T> 两者都没有。