Я пытаюсь повысить производительность определенной части моей программы, которая включает в себя глубокое клонирование одного и того же графа объектов снова и снова в нескольких потоках.В настоящее время я использую сериализацию, которая является хорошей легкой реализацией, но я хотел бы что-то быстрее.Я наткнулся на идею клонирования IL и пытаюсь поработать с кодом, найденным здесь (блог Whizzo) .
Я пока не получаю IL, поэтому я надеюськто-то может немного помочь и объяснить мне некоторые вещи (я думаю, это первый вопрос из нескольких).
Вопрос здесь (и, между прочим, если у кого-то есть хорошие ссылки, объясняющие коды операций и рефлексию. Допустите немного больше, что было бы здорово, MSDN не дает много деталей), как копируются значения?Я вижу, что новый объект создается и извлекается из стека
generator.Emit(OpCodes.Newobj, cInfo);
generator.Emit(OpCodes.Stloc, cloneVariable);
Затем немного позже, учитывая интересующее значение поля, значение каким-то образом копируется.Я не понимаю, как мы возвращаемся к исходному объекту и получаем его значение, когда на исходный объект, похоже, нет ссылки?Или это какая-то магия LocalBuilder (я не уверен на 100%, что он делает):
// I *THINK* this Pushes the cloneVariable on the stack, loads an argument (from where?) and sets the field value based on the FieldInfo??
generator.Emit(OpCodes.Ldloc, cloneVariable);
generator.Emit(OpCodes.Ldarg_0);
generator.Emit(OpCodes.Ldfld, field);
generator.Emit(OpCodes.Stfld, field);
Я немного изменил код, так как всегда хочу клон Deep и хочу, чтобы он основывался насериализованные поля:
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);
}