I have a value (struct instance) that was cast to object
for generic handling. I need to make a copy of the value. I cannot do this explicitly because I just have its Type
and don't know what it is in compile time.
By default I get a copy of reference: var copy = objectOfMyStruct;
. I thought about making an explicit shallow copy by MemberwiseClone()
but I cannot do this because it's protected method and I cannot modify MyStruct
.
Convert.ChangeType(objectOfMyStruct, typeOfMyStruct)
doesn't help because conversion (actually no conversion) happens inside and it returns Object again.
How could I do this?
EDIT:
I need to make a copy to preserve original value and just deserialized one to pass to OnChangeHandler. Simplified implementation is:
var oldValue = type.GetValue(reference);
var newValue = oldValue; // something better is needed here
Deserialize(type, stream, ref newValue);
OnChange(oldValue, newValue);
type.SetValue(reference, newValue);
Copy is made because only delta (changes) are sent so should be applied to the original value.
EDIT 2:
This implementation works fine for primitive types, so despite int is boxed too I'm copying it instead of copying reference to it. I just don't understand this.
Here is an example of what is needed.
This example, which you can test in LINQPad should make a clone of the struct without casting it back to its unboxed type, so that when it is mutated by a call through the implemented interface, only the original is mutated. The question is thus; how do I write that Clone method?
void Main()
{
object original = new Dummy { Property = 42, Field = "Meaning of life" };
object clone = Clone(original);
((IDummy)original).Mutate(); // will modify the boxed struct in-place
original.Dump();
// should output different if Clone did its job
clone.Dump();
}
static object Clone(object input)
{
return input;
}
public interface IDummy
{
void Mutate();
}
public struct Dummy : IDummy
{
public int Property { get; set; }
public string Field;
public void Mutate()
{
Property = 77;
Field = "Mutated";
}
}
You can simply use copy = Object. create(originalObj); but you may want to use copy = JSON. parse(JSON. stringify(originalObj)); to avoid any reference in sub objects (Deep Copy).
To clone an object, use the Object class's clone() method. It is the quickest way to duplicate an array. The class whose object clone we wish to generate must implement the Cloneable interface. If the Cloneable interface is not implemented, the clone() function throws a CloneNotSupportedException .
I assume that you not only want to make a copy, but also be able to actually use that copy.
And in order to use it, you need to cast (unbox) it to the appropriate type, which effectively makes a copy. In fact, even putting the value into the box already resulted in a copy.
So, if (for example) you know that these objects are either ints or floats, you could do:
if (obj is int)
{
int i = (int) obj;
// do something with the copy in i
}
else if (obj is float)
{
float f = (float) obj;
// do something with the copy in f
}
If you have a large number of types to evaluate, you can use a switch
statement or even a Dictionary<Type,Action<object>>
.
If you need to deal with types that you don't know about at compile time (some type added dynamically thorugh some kind of plugin mechanism) than this won't be possible, but then again, it would also not be possible to do anything with the object (unless through an interface).
UPDATE:
Now that you changed your question, here's a better answer: you do no need to make a copy, it has been made for you by boxing the struct.
Example:
int i = 42;
// make a copy on the heap
object obj = i;
// modify the original
i = i + 1;
// copy is not modified
Debug.Assert((int)obj == 42);
Obviously, I'm using int
here for convenience, but it is true for every struct. If the struct implements an interface, you can cast the object to that interface (that won't make a second copy) and use it. It will not modify the orginal value, because it is operating on the copy in the box.
UPDATE 2:
Just to be very explicit: this works for every struct. For example:
interface IIncrementor
{
void Increment();
}
struct MyStruct : IIncrementor
{
public int i;
public void Increment()
{
this.i = this.i + 1;
}
public override string ToString()
{
return i.ToString();
}
}
// in some method:
MyStruct ms = new MyStruct();
ms.i = 42;
Console.Writeline(ms); // 42
object obj = ms;
IIncrementable ii = (IIncrementable) obj;
ii.Increment();
Console.Writeline(ms); // still 42
Console.Writeline(ii); // 43
One more UPDATE:
instead of
object original = new Dummy { Property = 42, Field = "Meaning of life" };
object clone = Clone(original);
write
Dummy original = new Dummy { Property = 42, Field = "Meaning of life" };
object clone = original;
and you'll be fine.
Thanks for the LINQPad example, it greatly clarified your question and it gave me a starting point for coming up with a solution.
This is a very brute-force solution, but it might serve your purpose, until somebody comes up with a more elegant answer:
static object Clone(object input)
{
IntPtr p = Marshal.AllocHGlobal(Marshal.SizeOf(input));
try
{
Marshal.StructureToPtr(input, p, false);
return Marshal.PtrToStructure(p, input.GetType());
}
finally
{
Marshal.FreeHGlobal(p);
}
}
This is how it works:
StructureToPtr
unboxes your input and copies it into unmanaged memory:
If structure is a value type, it can be boxed or unboxed. If it is boxed, it is unboxed before copying.
PtrToStructure
creates a new structure, boxes it and returns it:
You can pass a value type to this overload method. In this case, the returned object is a boxed instance.
The unmanaged memory is freed.
Here's another answer:
static object Clone(object input) =>
typeof(object)
.GetMethod("MemberwiseClone", BindingFlags.NonPublic | BindingFlags.Instance)
.Invoke(input, null);
It uses the Object.MemberwiseClone method. This method is protected, which is why I have to call it via reflection.
This approach works fine with enums, and with structs that have [StructLayout(LayoutKind.Auto)]
.
If the list of types to handle this cloning for is controlled, that is, you know which types you need to handle this for, then I would simply create a dictionary that contains functions that knows how to handle each particular type.
Here's a LINQPad example:
void Main()
{
_CloneMapping[typeof(Dummy)] = (object obj) =>
{
Dummy d = (Dummy)obj;
return new Dummy { Field = d.Field, Property = d.Property };
};
object original = new Dummy { Property = 42, Field = "Meaning of life" };
object clone = Clone(original);
((IDummy)original).Mutate(); // will modify the boxed struct in-place
original.Dump();
// should output different if Clone did its job
clone.Dump();
}
static readonly Dictionary<Type, Func<object, object>> _CloneMapping = new Dictionary<Type, Func<object, object>>();
static object Clone(object input)
{
if (input == null)
return null;
var cloneable = input as ICloneable;
if (cloneable != null)
return cloneable.Clone();
Func<object, object> cloner;
if (_CloneMapping.TryGetValue(input.GetType(), out cloner))
return cloner(input);
throw new NotSupportedException();
}
public interface IDummy
{
void Mutate();
}
public struct Dummy : IDummy
{
public int Property { get; set; }
public string Field;
public void Mutate()
{
Property = 77;
Field = "Mutated";
}
}
This will output:
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With