如何保证自己不会错误地更新当前对象上的另一个对象?

时间:2011-04-06 12:49:59

标签: c# java .net design-patterns

当我使用引用类型时,你能建议我一种方法可以防止我出现这种情况吗?

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!!

其余的故事是关于调试以找出为什么某些成本价格更新。

我希望通过此示例简化问题。如果你明白我的意思,我希望。

问题 :您能否建议我避免重复此类错误?更新引用类型的值时的任何设计模式。

9 个答案:

答案 0 :(得分:8)

您的Price对象应该是不可变的 - 这将迫使您分配新的Price对象,而不是更改现有对象的价格,从而避免副作用。

答案 1 :(得分:2)

取决于您希望通过此行实现的目标:

 candyCost.Price = someCost.Price;

您想说,candyCostsomeCost目前具有相同的价格 总是具有相同的价格?

如果您只想将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)

有几种方法可以做到。

  1. 使用不可变类型 - 例如Java中的字符串,以及所有原始包装器
  2. 使用复制构造函数复制对象而不是引用它们
  3. 一开始,不变性似乎是一种非常痛苦的限制性方法,但实际上它很常见,并强制执行你想要做的事情。

    使用复制构造函数意味着你必须确保无论何时返回一个对象(例如从getter)你实际创建一个新对象,类似地,当你使用传入的对象(例如setter)时,你需要复制它。 / p>

答案 7 :(得分:0)

使用{get;将Cost.Price设为只读私人集;} 在Cost中添加一个名为SetPrice的新方法,该方法接受Price并创建一个新的Price实例

SetPrice(Price price)
{
    this.Price = price.Clone();
}

您需要使Price实施IClonnable

答案 8 :(得分:0)

根据语言,您可以执行运算符重载。因此,重载赋值运算符(=)并在重载的运算符体中执行深度克隆。