I am trying to improve the performance of a certain part of my program, which includes deep cloning of the same object graph multiple times. I am currently using serialization, which is an easy easy implementation, but I would like something faster. I stumbled upon the idea of cloning IL and am trying to work with some code found here (Whizzo Blog) .
Actually, I am not getting IL yet, so I hope someone can help a little and explain some things to me (I think this is the first question of a few).
The question is here (and btw, if anyone has good links explaining opcodes and reflection.emit a bit more, which would be great, MSDN doesn't give much details), how are the values copied? I see that a new object is being built and pushed out of the stack
generator.Emit(OpCodes.Newobj, cInfo); generator.Emit(OpCodes.Stloc, cloneVariable);
Then a little later the set value of the field, the value of which is somehow copied. I do not understand how we return to the original object and evaluate it when the original object does not seem to be referenced? Or is this some kind of LocalBuilder magic (I'm not 100% sure what it does):
I changed the code a bit, because I always need a Deep clone, and I want it based on serialized fields:
private static T CloneObjectWithILDeep(T myObject) { Delegate myExec = null; if (!_cachedILDeep.TryGetValue(typeof(T), out myExec)) { // Create ILGenerator DynamicMethod dymMethod = new DynamicMethod("DoDeepClone", typeof(T), new Type[] { typeof(T) }, Assembly.GetExecutingAssembly().ManifestModule, true); ILGenerator generator = dymMethod.GetILGenerator(); LocalBuilder cloneVariable = generator.DeclareLocal(myObject.GetType()); ConstructorInfo cInfo = myObject.GetType().GetConstructor(Type.EmptyTypes); generator.Emit(OpCodes.Newobj, cInfo); generator.Emit(OpCodes.Stloc, cloneVariable); foreach (FieldInfo field in typeof(T).GetFields(System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Public)) { if(field.IsNotSerialized) continue; if (field.FieldType.IsValueType || field.FieldType == typeof(string)) { generator.Emit(OpCodes.Ldloc, cloneVariable); generator.Emit(OpCodes.Ldarg_0); generator.Emit(OpCodes.Ldfld, field); generator.Emit(OpCodes.Stfld, field); } else if (field.FieldType.IsClass) { CopyReferenceType(generator, cloneVariable, field); } } generator.Emit(OpCodes.Ldloc_0); generator.Emit(OpCodes.Ret); myExec = dymMethod.CreateDelegate(typeof(Func<T, T>)); _cachedILDeep.Add(typeof(T), myExec); } return ((Func<T, T>)myExec)(myObject); }