同一类的两个对象,其中一个被覆盖

本文关键字:一个 覆盖 两个 一类 对象 | 更新日期: 2023-09-27 18:03:14

我有两个类型为ProductInformation的对象,它们包含productId、productName和price的属性。我还有一个方法,用于查询数据库中的这些信息,以填充产品类。

ProductInformation giftcard = query.ExecuteQuery(10) //this returns a giftcard
ProductInformation giftCertificate = query.ExecuteQuery(9) //this returns a gift certificate

我已经遍历了查询,并且可以确认,在运行第一行之后,礼品卡已成功填充。然而,不知何故,在我创建了礼品证书之后,它用礼品证书的属性覆盖了礼品卡对象。在我看来,它们应该是独立的对象。为了保留礼品卡,我遗漏了什么?

作为参考,我使用的查询基本上是

SELECT *
FROM Products
WHERE ProductName like '%gift card'

SELECT *
FROM Products
WHERE ProductName like '%gift certificate'

我唯一能想到的是,我的查询类有一个私有的ProductInformation对象,我用它来返回礼品卡和礼品证书,如

ProductInformation thisProduct;
public ProductInformation ExecuteQuery(int i)
{
    switch (i)
        case 10:
            thisProduct = GiftCard();
            break;
        case 9:
            thisProduct = GiftCertificate();
            break;
    return thisProduct;
 }
private ProductInformation GiftCard()
{
    using (SqlConnection con = new SqlConnection(conectionString))
    {
        con.Open();
        return con.query<ProductInformation>(giftCardQuery).First();
    }
}
private ProductInformation GiftCertificate()
{
    using (SqlConnection con = new SqlConnection(connectionString))
    {
        con.Open();
        return con.query<ProductInformation>(giftCertQuery).First();
    }
}

,但因为我分配thisProduct局部变量在我的测试方法,这应该创建类的新实例,对吗?

同一类的两个对象,其中一个被覆盖

"由于我将thisProduct分配给测试方法中的局部变量,这应该会创建类的新实例,对吧?"

不,赋值引用不会自动创建一个新的实例。

如果您使用相同的对象从数据库中读取,然后将该对象赋值给一个变量,希望它将创建一个单独的实例,那么这就是问题所在。您最终将得到对同一对象的两个引用,因此当您将下一个对象的数据读入其中时,它将覆盖前一个数据。

你应该为你想要读取的每个对象创建一个新的实例。

不像局部变量:

ProductInformation thisProduct;
ExecuteQuery(int i)
{
   switch (i)
      case 10:
          thisProduct = GiftCard();
          break;
       case 9:
          thisProduct = GiftCertificate();
          break;
    return thisProduct;
 }

您的Query类被用来加载两者,并且查询对象引用了相同的ProductInformation实例。在我看来,你有两个选择:

-使用2个query实例,因为你的查询类有状态(坏主意)。

-将ProductInformation thisProduct变量移动到 ExecuteQuery()方法中。

giftcard和giftCertificate都是同一个实例,第二个语句只是改变了现有的对象。我猜是放

thisProduct = new ProductInformation();
ExecuteQuery方法中的

before switch语句应该有帮助。而且看起来thisProduct不应该在类级别范围内。

ProductInformation该产品;

public ProductInformation ExecuteQuery(int i)
{
    thisProduct = new ProductInformation();
    switch (i)
        case 10:
            thisProduct = GiftCard();
            break;
        case 9:
            thisProduct = GiftCertificate();
            break;
    return thisProduct;
 }

这里的部分问题是LINQ的使用。执行被延迟到使用。这意味着对象本身可能没有变化,只是在您查询它之前它可能从未被设置过。

无论如何,您使用的模式相当奇怪。为什么不选择一种更侧重于存储库的数据访问方法呢?它比通过准单例来获取数据要干净得多。这也是一个更好的关注点分离。

@TMKeown有一个有趣的解决方案,可能会解决当前的问题,但作为架构师,我更关心您设置的解决问题的方式。你为什么要用这种方式把事情说出来。如果存在一个好的动机,那么就应该有一个模式来保持动机,而不会延续相关的问题(一个对象神奇地变成了另一个对象)。

进一步说明,ProductInformation是一个引用类型,引用类型总是通过引用传递给。此外,如果您在类级别声明它,则两个调用将返回相同的实例,此外,调用代码接收到在类级别声明的ProductInformation object相同的实例,并且在两个方法调用中使用相同的query对象。

因此,使用单独的ProductInformation对象实例的想法可以实现,如果你将该变量移动到这些方法中,那么它将在方法调用退出时被销毁,并在下一个方法调用开始时重新创建。

关于内存管理、引用和值类型的更多信息,请访问Eric Lippert的博客:

    Eric Lippert的博客-内存管理系列