Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How does MemberWiseClone create a new object with the cloned properties?

I wanted to create a more constrained version of MemberwiseClone, but realised the only way my own C# code can add properties to an object is to use dynamic, but that can't give the object the same type as the original. My other, uglier choice is to emit source for the new clone and compile it during runtime, but that carries complexities re. assembly references etc. that I do not care for in keeping things simple.

For now I'm just using MemberwiseClone, but am really curious as to how it works. I can't find any decompiled source.

like image 490
ProfK Avatar asked Feb 02 '17 09:02

ProfK


People also ask

How do I copy an object to another in C#?

In general, when we try to copy one object to another object, both the objects will share the same memory address. Normally, we use assignment operator, = , to copy the reference, not the object except when there is value type field. This operator will always copy the reference, not the actual object.


1 Answers

It's basically explained in the MemberwiseClone MSDN documentation:

The MemberwiseClone method creates a shallow copy by creating a new object, and then copying the nonstatic fields of the current object to the new object. If a field is a value type, a bit-by-bit copy of the field is performed. If a field is a reference type, the reference is copied but the referred object is not; therefore, the original object and its clone refer to the same object.

The actual implementation of the above is implemented internally by CLR. You can think of it as an optimized variant of the following standard C# code:

using System.Reflection;
using System.Runtime.Serialization;

public static object CustomMemberwiseClone(object source)
{
    var clone = FormatterServices.GetUninitializedObject(source.GetType());
    for (var type = source.GetType(); type != null; type = type.BaseType)
    {
        var fields = type.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly);
        foreach (var field in fields)
            field.SetValue(clone, field.GetValue(source));
    }
    return clone;
}

i.e. get the actual type, create a new instance of that type without calling any constructor and copy each instance field value from the source object.

Again, the actual internal implementation is different (as pointed in the comments), the above snippet is just to demonstrate the principle and how you can implement a method with the same semantics via reflection (which of course will be much slower than the CLR method).

ADDED BY THE OP: Please see Ivan's comments below for the further explanation I was seeking. I consider these part of his answer and will accept it based on them.

like image 74
Ivan Stoev Avatar answered Sep 21 '22 22:09

Ivan Stoev