C# 只允许一个 class 为 属性 调用不同的 class 的 setter (或者让 class 知道它是否存储在另一个 class)
C# Only allow one class to call a different class's setter for a property (Or have class know if it's stored in an array in another class )
假设我有两个 class,例如 Food
和 Barrel
。 Barrel
包含一组食物 private Food[] stores
以跟踪其中存储的内容。 Barrel
还包含访问和修改 stores
的方法,例如 public void Insert(Food)
和 public void Remove(Food)
.
所以Barrel
可以存储Food
。但我也希望 Food
知道它存储在哪里,如果有的话。例如,我想要一个方法 Food.Rot()
,如果食物没有储存,它只会腐烂食物。
我目前的解决方案是在 Food
中有一个 属性 public Barrel Container { get; set; }
来跟踪它所存储的 Barrel
的实例,并设置 Barrel.Insert(Food toAdd)
toAdd.Container
为自身,Barrel.Remove(Food toRemove)
将 toRemove.Container
设置为 null
(在这种情况下 Food.Rot()
实际上会腐烂食物)。
然而,任何其他 class 也可以访问 Food.Container
,如果他们写入,原始 Barrel
仍然有stores
中的此 Food
实例,但 Food.Container
将不再反映该实例。
我可以让 set 方法确保当 Food.Container
改变时,它首先调用 Container.Remove(this)
,但我真的不希望除了 Barrel
之外的任何东西都能够设置 Food.Container
排在首位。
我也可以做到 Food
根本不存储它的容器,只是让 Rot()
调用一个方法 bool IsStored()
来检查每个 Barrel.stores
看看调用它的 Food
class 的实例是否存储在里面,这样就没有双向恶意,但这对于优化来说似乎很糟糕。
感觉我在这个设计的某个地方违反了 OOP,我希望理想情况下整个情况需要重新设计。我也非常愿意接受这样的反馈。
当 Food 添加到 Barrel 时,您必须修改 Barrel 属性 食物。此外,如果设置了 Barrel 属性,则必须将食物添加到 Barrel 中(如果不存在)。检查是否存在很重要,否则,这两者将相互调用导致 Whosebug 异常。
删除时也必须重复相同的方法。这是您需要的示例:
public class Food
{
public string Name { get; set; }
private Barrel _barrel;
public Barrel Barrel
{
get
{
return _barrel;
}
set
{
if (_barrel != null && _barrel != value)
{
_barrel.Remove(this);
}
if (value != null)
{
value.Insert(this);
}
_barrel = value;
}
}
public override string ToString()
{
return Name+"@"+ Barrel??"";
}
}
public class Barrel
{
public string Name { get; set; }
public List<Food> Stores { get; set; } = new List<Food>();
public void Insert(Food food)
{
if (!Stores.Contains(food))
{
Stores.Add(food);
food.Barrel = this;
}
}
public void Remove(Food food)
{
if (Stores.Contains(food))
{
Stores.Remove(food);
food.Barrel = null;
}
}
public override string ToString()
{
return Name;
}
}
测试代码:
Barrel b0 = new Barrel() { Name = "Barrel 0" };
Barrel b1 = new Barrel() { Name = "Barrel 1" };
//Use insert method.
Food fish = new Food() { Name = "Fish" };
//I will insert fish to b0 first.
b0.Insert(fish);
b1.Insert(fish);
//Assign barrel directly
Food chicken = new Food() { Barrel = b0, Name = "Chicken" };
//then change barrel
chicken.Barrel = b1;
Debug.WriteLine("Barrel 1:"+ string.Join(",",b1.Stores));
//Modify Barrel attribute
chicken.Barrel = null;
Debug.WriteLine("Barrel 1:" + string.Join(",", b1.Stores));
//Remove from stores
b1.Remove(fish);
Debug.WriteLine("Barrel 1:" + string.Join(",", b1.Stores));
输出:
Barrel 1:Fish@Barrel 1,Chicken@Barrel 1
Barrel 1:Fish@Barrel 1
Barrel 1:
假设我有两个 class,例如 Food
和 Barrel
。 Barrel
包含一组食物 private Food[] stores
以跟踪其中存储的内容。 Barrel
还包含访问和修改 stores
的方法,例如 public void Insert(Food)
和 public void Remove(Food)
.
所以Barrel
可以存储Food
。但我也希望 Food
知道它存储在哪里,如果有的话。例如,我想要一个方法 Food.Rot()
,如果食物没有储存,它只会腐烂食物。
我目前的解决方案是在 Food
中有一个 属性 public Barrel Container { get; set; }
来跟踪它所存储的 Barrel
的实例,并设置 Barrel.Insert(Food toAdd)
toAdd.Container
为自身,Barrel.Remove(Food toRemove)
将 toRemove.Container
设置为 null
(在这种情况下 Food.Rot()
实际上会腐烂食物)。
然而,任何其他 class 也可以访问 Food.Container
,如果他们写入,原始 Barrel
仍然有stores
中的此 Food
实例,但 Food.Container
将不再反映该实例。
我可以让 set 方法确保当 Food.Container
改变时,它首先调用 Container.Remove(this)
,但我真的不希望除了 Barrel
之外的任何东西都能够设置 Food.Container
排在首位。
我也可以做到 Food
根本不存储它的容器,只是让 Rot()
调用一个方法 bool IsStored()
来检查每个 Barrel.stores
看看调用它的 Food
class 的实例是否存储在里面,这样就没有双向恶意,但这对于优化来说似乎很糟糕。
感觉我在这个设计的某个地方违反了 OOP,我希望理想情况下整个情况需要重新设计。我也非常愿意接受这样的反馈。
当 Food 添加到 Barrel 时,您必须修改 Barrel 属性 食物。此外,如果设置了 Barrel 属性,则必须将食物添加到 Barrel 中(如果不存在)。检查是否存在很重要,否则,这两者将相互调用导致 Whosebug 异常。
删除时也必须重复相同的方法。这是您需要的示例:
public class Food
{
public string Name { get; set; }
private Barrel _barrel;
public Barrel Barrel
{
get
{
return _barrel;
}
set
{
if (_barrel != null && _barrel != value)
{
_barrel.Remove(this);
}
if (value != null)
{
value.Insert(this);
}
_barrel = value;
}
}
public override string ToString()
{
return Name+"@"+ Barrel??"";
}
}
public class Barrel
{
public string Name { get; set; }
public List<Food> Stores { get; set; } = new List<Food>();
public void Insert(Food food)
{
if (!Stores.Contains(food))
{
Stores.Add(food);
food.Barrel = this;
}
}
public void Remove(Food food)
{
if (Stores.Contains(food))
{
Stores.Remove(food);
food.Barrel = null;
}
}
public override string ToString()
{
return Name;
}
}
测试代码:
Barrel b0 = new Barrel() { Name = "Barrel 0" };
Barrel b1 = new Barrel() { Name = "Barrel 1" };
//Use insert method.
Food fish = new Food() { Name = "Fish" };
//I will insert fish to b0 first.
b0.Insert(fish);
b1.Insert(fish);
//Assign barrel directly
Food chicken = new Food() { Barrel = b0, Name = "Chicken" };
//then change barrel
chicken.Barrel = b1;
Debug.WriteLine("Barrel 1:"+ string.Join(",",b1.Stores));
//Modify Barrel attribute
chicken.Barrel = null;
Debug.WriteLine("Barrel 1:" + string.Join(",", b1.Stores));
//Remove from stores
b1.Remove(fish);
Debug.WriteLine("Barrel 1:" + string.Join(",", b1.Stores));
输出:
Barrel 1:Fish@Barrel 1,Chicken@Barrel 1
Barrel 1:Fish@Barrel 1
Barrel 1: