c#对象引用不会更改

时间:2012-10-16 16:30:19

标签: c# reference dispose idisposable

我需要编写一个包装器,当代码超出当前范围时,在现有对象上执行某些操作。

代码如下所示:

public class ObjWrapper : IDisposable
{
   private KnownType dt = null;

   public ObjWrapper(KnownType data)
   {
      this.dt = data;
   }

   public void Dispose()
   {
      SaveKnownTypeInDB(this.dt);
   }
}

电话会是这样的:

KnownType data = new KnownType();
// do something on `data`

using (ObjWrapper ow = new ObjWrapper(data))
{
  // do something on `data`
}

我总是在数据库中获取来自对象原始状态的值。当我在Dispose()中放置一个断点时,我可以确认它有原始值。当我在堆栈上检查调用方法时,我在构造函数中传递的对象具有正确的值。我期望data对象通过引用传递,并且在ObjWrapper内调用的所有属性都具有'updated'值。我还试图在构造函数中使用ref传递数据,或者将数据作为属性放到ObjWrapper并在构造函数之后设置它,但它完全相同。任何想法为什么?我认为对于这种对象,c#正在使用引用...

感谢。

更新

5 个答案:

答案 0 :(得分:2)

  

预期的行为是当我在Dispose中放置一个断点时,我只看到初始数据状态。

由于KnownType而不是 struct ,因此您始终在ObjWrapper内分配引用。因此,您对data所做的任何更改都将反映在包装器内部。

  

我认为对于这种对象,c#正在使用引用...

这就是你看到对象当前状态的原因。由于您要存储对原始实例的引用,因此对该实例的任何更改也将反映在该引用中。

如果要保存数据的副本,则需要自行制作副本。这可能意味着手动复制值。

答案 1 :(得分:1)

问题的大部分仍然是基于你没有展示过的代码,但现在已经足够做出有根据的猜测了。

我会假设KnownType是一个班级。作为一个类,它是一个参考类型。这意味着任何变量(例如data)实际上不包含KnownType对象包含的任何数据;变量只包含一个存在于“其他地方”的实际KnownType对象的引用(也就是内存中的一个位置)。

当您将KnownType对象传递给构造函数时,您将按值传递它,但该值只是一个引用。这意味着您正在制作参考的副本。这两个引用都指向同一个实际对象。因此,如果它们指向的实际对象都被更改,则两个变量都“看到”更改。但是,如果您更改哪个变量指向哪个对象,则另一个变量将不知道该更改。因此,如果您没有看到数据库中反映的更改,那么它的含义是,而不是改变使用中的现有data对象,而是指定一个全新的KnownType对象那个变量。 (你没有展示这个代码,所以很难肯定地说。)

所以,第一个解决方案就是不要那么做。请勿更改data指向的内容,只需改变您传递到data的{​​{1}}对象。

如果能够将新的ObjWrapper分配给KnownType并将新的data设置为保存的那个,那么你可以做类似的事情(我不建议)如果你可以避免它,因为它在语义上相当奇怪,使它容易出错。)

public class ObjWrapper : IDisposable
{
    private Func<KnownType> functor;
    public ObjWrapper(Func<KnownType> functor)
    {
        this.functor = functor;
    }
    public void Dispose()
    {
        SaveKnownTypeInDB(functor());
    }
}

并使用它:

KnownType data = new KnownType();
// do something on `data`

using (ObjWrapper ow = new ObjWrapper(() => data))
{
    // do something on `data`
}

答案 2 :(得分:0)

您需要了解Reference和Value类型之间的区别。您没有传递对象的副本,而是传递对该对象的引用。我猜你需要在你的ObjWrapper类的构造函数中实现/调用深层复制机制

答案 3 :(得分:0)

你应该实现Dispose()方法来释放资源。如果您没有显式调用Dispose()方法,则无法确定何时执行它。建议不要编写除资源释放之外的任何逻辑或代码。

答案 4 :(得分:0)

我找到了发生这种情况的原因:

  • 对象的初始状态(在进入构造函数之前)接近'new'(其中大多数成员,至少在监视窗口中可见的那些成员都具有'default'值);
  • 在包装器的范围内,该对象被传递给各种函数。其中一个基于某种逻辑,决定“重新创建”对象,并用另一个对象的属性填充它的属性;
  • 当然,这意味着原始对象的引用在包装器的范围内发生了变化;
  • 外部,在包装类'中,'reference'仍然“指向”旧对象。

根据新的事实,这是正常和预期的行为。我要感谢大家的帮助和建议!