Unexpected interaction of ValueType, Reflection and ref parameter

  • Thread starter Thread starter Guest
  • Start date Start date
G

Guest

I posted a question yesterday under the Subject "How can I copy a value type
dynamically without knowing the type". Unfortunately, I did not tie the
problem down to a real code example. After further investigation, though, I
have managed to create a real example of the problem.

My original question was how to create a copy of a Value Type dynamically so
that it does a copy-by-value rather than copying a reference to the same
boxed object. The answer given was simply to use the code shown below as
'CopyValueType', which worked in all of the simple examples shown. This
confused me for a while until I discovered that the code which was
subsequently manipulating the variable was using reflection to call a method
and passing this variable as a ref parameter. This combination shows the
problem, as demonstrated in the code below.

static void Main()
{
int i = 0;
Process(i);
}

private static ValueType CopyValueType(ValueType i)
{
return i;
}

private static void Process(ValueType i)
{
ValueType j = CopyValueType(i);

Console.WriteLine("Original i = " + i.ToString());
Console.WriteLine("Original j = " + j.ToString());

OtherCode(j);

Console.WriteLine("i is now = " + i.ToString());
Console.WriteLine("j is now = " + j.ToString());

Console.Read();
}

private static void OtherCode(ValueType x)
{
MethodInfo method = typeof(Class1).GetMethod("Update", BindingFlags.Static
| BindingFlags.NonPublic);
method.Invoke(null, new object[] { x });
}

private static void Update(ref int v)
{
v = 1;
}

If you execute this, you get:

Original i = 0
Original j = 0
i is now = 1
j is now = 1

As you can see, both i and j have been modified by the call to Update via
reflection - so the return value from 'CopyValueType' is clearly not a
completely separate copy from the input parameter, but must still be a
reference to the same original variable.

My requirement is to be able to implement the 'Process' method above without
having control of the input parameter (except that it is a ValueType) and
without knowing what code is in the 'OtherCode' method. The requirement is
simply to make a copy of the input variable and pass it on in such a way that
the subsequent code cannot modify the original variable. So I think I'm back
to my original need for an implementation of 'CopyValueType' that creates a
copy of the input parameter rather than a reference to it.

Any help would be greatly appreciated.
 
Robert Matheson said:
I posted a question yesterday under the Subject "How can I copy a value
type
dynamically without knowing the type". Unfortunately, I did not tie the
problem down to a real code example. After further investigation, though,
I
have managed to create a real example of the problem.

My original question was how to create a copy of a Value Type dynamically
so
that it does a copy-by-value rather than copying a reference to the same
boxed object. The answer given was simply to use the code shown below as
'CopyValueType', which worked in all of the simple examples shown. This
confused me for a while until I discovered that the code which was
subsequently manipulating the variable was using reflection to call a
method
and passing this variable as a ref parameter. This combination shows the
problem, as demonstrated in the code below.
....
My requirement is to be able to implement the 'Process' method above
without
having control of the input parameter (except that it is a ValueType) and
without knowing what code is in the 'OtherCode' method. The requirement is
simply to make a copy of the input variable and pass it on in such a way
that
the subsequent code cannot modify the original variable. So I think I'm
back
to my original need for an implementation of 'CopyValueType' that creates
a
copy of the input parameter rather than a reference to it.

If a particular ValueType instance happens to implement IClonable, then you
can call IClonable.Clone to get an independant copy. In other cases, if it
can be serialized, then you can serialize to a MemoryStream then deserialize
from the same stream to get a copy.

Otherwise, you're going to have to try to brute-force it by using reflection
to copy the guts of the object, and hope that this accurately copies the
state. Since a ValueType is probably not that complex, you may succeed.

John Saunders
 
Back
Top