Reputation: 1271
I need to write a wrapper that when the code goes out of current scope, performs something on an existing object.
The code looks like this:
public class ObjWrapper : IDisposable
{
private KnownType dt = null;
public ObjWrapper(KnownType data)
{
this.dt = data;
}
public void Dispose()
{
SaveKnownTypeInDB(this.dt);
}
}
And the call would look like this:
KnownType data = new KnownType();
// do something on `data`
using (ObjWrapper ow = new ObjWrapper(data))
{
// do something on `data`
}
I'm always getting the values in the database coming from original state of the object. When I am putting a breakpoint inside Dispose(), I can confirm that it has the original values. When I am checking on the stack the caller-method, the object I passed in the constructor has the correct values. I was expecting that the data
object is passed by reference and all properties called inside ObjWrapper
have the 'updated' values. I tried also to pass the data with ref
in the constructor, or to put the Data as a property to ObjWrapper
and to set it right after the constructor, but it is all the same. Any ideea why? I thought that for this kind of objects c# is using references ...
Thanks.
Updated
Upvotes: 0
Views: 479
Reputation: 1271
I have found the reason why this was happening:
This is normal and expected behaviour in the light of the new facts. I want to thank you all for your help and suggestions!
Upvotes: 0
Reputation: 203820
So much of the problem is still based on code you haven't shown, but there is now enough to make an educated guess.
I will assume that KnownType
is a class. Being a class it is a reference type. That means that any variable (such as data
) doesn't actually contain whatever data a KnownType
object contains; the variable will just contain a reference (aka a location in memory) of an actual KnownType
object that exists "somewhere else".
When you pass the KnownType
object to the constructor, you're passing it by value, but that value is just a reference. This means you're making a copy of the reference. The two references both point to the same actual object. Because of this, if the actual object that they both point to is changed, both variables "see" the change. However, if you change which object either variable points to, the other variable will have no idea about that change. Therefore, if you aren't seeing your changes reflected in the database save what it means is that rather than mutating the existing data
object inside of the using, you're assigning an entirely new KnownType
object to that variable. (You haven't shown this code, so it's hard to say that with certainty.)
So, the first solution would just be don't do that. Don't change what data
points to, just mutate the data
object that you passed into the ObjWrapper
.
If it's real important that you be able to assign a new KnownType
to data
and have that new one be the one that is saved, you could do something like this (I don't suggest it if you can avoid it though, as it's rather odd semantically, making it bug prone.)
public class ObjWrapper : IDisposable
{
private Func<KnownType> functor;
public ObjWrapper(Func<KnownType> functor)
{
this.functor = functor;
}
public void Dispose()
{
SaveKnownTypeInDB(functor());
}
}
and to use it:
KnownType data = new KnownType();
// do something on `data`
using (ObjWrapper ow = new ObjWrapper(() => data))
{
// do something on `data`
}
Upvotes: 1
Reputation: 1062
you are supposed to implement Dispose() method to release the resources. If you are not calling Dispose() method explicitly, you can't determine when it will be executed. It is advised not to write any logic or code other than resource releasing.
Upvotes: 0
Reputation: 3494
You need to understand the difference between Reference and Value types. You are not passing a copy of the object, you are passing a reference to the object. I would guess that you need to implement/invoke a deep copy mechanism in the constructor of your ObjWrapper class
Upvotes: 0
Reputation: 564413
Expected behaviour is that when I put a breakpoint in Dispose I see only initial state of data.
Since KnownType
is a class and not a struct, you're always assigning a reference inside of ObjWrapper
. As such, any changes you make to data
will be reflected inside of the wrapper, as well.
I thought that for this kind of objects c# is using references ...
It is, which is why you're seeing the current state of the object. Since you're storing a reference to the original instance, any changes to the instance will be reflected in that reference as well.
If you want to save a copy of the data, you'll need to make the copy yourself. This will likely mean copying the values manually.
Upvotes: 2