Reputation: 116
I'm trying to understand persistent memory in C# and don't know why this code is not keeping the change made in one of the functions.
using System;
using System.Runtime.InteropServices;
public class Test2
{
public struct value
{
public int sz;
}
public static void Main(string[] args)
{
one foo1 = new one(one_full);
two foo2 = new two(two_full);
make_calls(foo1, foo2);
}
public delegate void one(IntPtr ctx);
public static void one_full(IntPtr ctx)
{
/* set sz and see if persists */
GCHandle gch = GCHandle.FromIntPtr(ctx);
value val = (value)gch.Target;
val.sz = 6;
Console.WriteLine("Changed sz to be 6");
}
public delegate void two(IntPtr ctx);
public static void two_full(IntPtr ctx)
{
GCHandle gch = GCHandle.FromIntPtr(ctx);
value val = (value)gch.Target;
Console.Write("sz is = ");
Console.WriteLine(val.sz);
}
public static void make_calls(one f_one, two f_two)
{
value test = new value();
test.sz = 0;
IntPtr ptr = GCHandle.ToIntPtr(GCHandle.Alloc(test));
f_one(ptr);
f_two(ptr);
}
}
I know it's missing the free at the end but that is just leading to messy memory management.... I'm looking for if someone can help me out and explain why sz does not stay as the value 6 for when the second function is called...
The output when ran is:
Changed sz to be 6
sz is = 0
Upvotes: 2
Views: 113
Reputation: 20754
Becuase value
is a sturct
and structs are not reference types. when you have an instance of a struct and var b = instanceOfStruct
then b
is a new struct not a reference to instanceOfStruct
. Chaning values in b
does not reflect to instanceOfStruct
.
In your code:
value val = (value)gch.Target;
will create a new instance of value
struct which has same values as the structs that gch.Target
point to it. Changing val
does not change the struct behind gch.Target
. The problem is because of a confusion between value types and reference types in C#. If you change value
type to a class instead of struct
then you will get the desired result. You can also use dynamic
to modify the struct which is target of the handle:
dynamic val = gch.Target;
val.sz = 6;
Upvotes: 1
Reputation: 14894
It's all because value
is a struct
.
GCHandle.Alloc
takes an object
parameter, so if you pass a struct
, it has to be boxed.
Later when you use
value val = (value)gch.Target;
it has to be unboxed, so a copy of it is stored in val
. Any modifications you make later are made on the copy, not on the boxed struct
.
It has nothing to do with GCHandle
, it's how value types (struct
s) work in C#. That's why it's recommended to make value types immutable.
Upvotes: 2