当我使用引用类型时,你能建议我一种方法可以防止我出现这种情况吗?
var someCost = new Cost( Price: new Price(1000, "USD")
, CostType: "Type-A") ;
var candyCost = new Cost();
// Initialize candyCost.Price
candyCost.Price = someCost.Price; //Now candyCost Price is referencing
// price of someCost;
// (.......)
// Some logic and code here
//and I forgot that I was referencing to someCost object's price object
//and I do stupid mistake:
candyCost.Price.Value = 5000; //Now I believe I have updated candyCost price
//but I have also updated someCost!!
其余的故事是关于调试以找出为什么某些成本价格更新。
我希望通过此示例简化问题。如果你明白我的意思,我希望。
问题 :您能否建议我避免重复此类错误?更新引用类型的值时的任何设计模式。
答案 0 :(得分:8)
您的Price
对象应该是不可变的 - 这将迫使您分配新的Price
对象,而不是更改现有对象的价格,从而避免副作用。
答案 1 :(得分:2)
取决于您希望通过此行实现的目标:
candyCost.Price = someCost.Price;
您想说,candyCost
和someCost
目前具有相同的价格 或总是具有相同的价格?
如果您只想将candyCost.Price
的值等于初始化为someCost.Prize
,则应克隆Price
实例:
candyCost.Price = new Price(someCost.Price); // copy constructor pattern inside
(当然你必须实现构造函数)
答案 2 :(得分:1)
通过永远创建两个代表相同内容的局部变量。
答案 3 :(得分:1)
通过实施IClonnable接口创建类Price的深层副本。然后当你指定价格时,你会说
a.Price = b.Price.Clone(); // will return a new object of the price after assigning the internal value types
或
Class Cost{
private Price _price;
public Price PriceValue
{
get { _price.Clone(); }
set { _price = value; }
}
}
这样你永远不会忘记
因此您无法直接访问_price字段,除非您调用Getter属性,该属性最终会返回Price的深层副本
答案 4 :(得分:0)
在这种情况下,我建议使用struct
(值类型)而不是class
(引用类型)。这样就不可能引用同一个实例,因为没有'引用',值本身就存储了:)
您还可以将Price
类型的属性设置为只读,并且只能由构造函数设置。这样你可以引用另一个副本,但这没有问题 - 它们都将保持相同的值,因为设置为创建新对象所需的新值。
答案 5 :(得分:0)
您想要Price属性的按值行为。 getter应该返回Price对象的副本。
答案 6 :(得分:0)
有几种方法可以做到。
一开始,不变性似乎是一种非常痛苦的限制性方法,但实际上它很常见,并强制执行你想要做的事情。
使用复制构造函数意味着你必须确保无论何时返回一个对象(例如从getter)你实际创建一个新对象,类似地,当你使用传入的对象(例如setter)时,你需要复制它。 / p>
答案 7 :(得分:0)
使用{get;将Cost.Price设为只读私人集;} 在Cost中添加一个名为SetPrice的新方法,该方法接受Price并创建一个新的Price实例
SetPrice(Price price)
{
this.Price = price.Clone();
}
您需要使Price实施IClonnable
答案 8 :(得分:0)
根据语言,您可以执行运算符重载。因此,重载赋值运算符(=
)并在重载的运算符体中执行深度克隆。