Мы широко используем Snapshotter от Dapper, поэтому выявляем изменения свойств, чтобы сделать обновления более эффективными. Сейчас мы хотим использовать его для определения изменений, которые можно было бы использовать для регистрации. Для этого нам нужно добавить свойство OldValue
во вложенный класс Changes
(который имеет Name
и NewValue
).
Вся информация есть в этом классе, но она использует библиотеку Emit. Я пробовал различные добавления строк, пытаясь получить доступ к значению этого исходного свойства и установить его на OldValue
:
например.
il.Emit(OpCodes.Callvirt, typeof(Change).GetMethod("set_OldValue"));
Однако я продолжаю получать сообщения о том, что это дестабилизирует среду выполнения. Мне нравится возиться, но библиотека Emit - это совершенно новая почва. Я надеялся, что кто-то (... https://stackoverflow.com/users/23354/marc-gravell...https://stackoverflow.com/users/13249/nick-craver) со знанием дела может направить меня сюда.
private static Func<T, T, List<Change>> GenerateDiffer()
{
var dm = new DynamicMethod("DoDiff", typeof(List<Change>), new Type[] { typeof(T), typeof(T) }, true);
var il = dm.GetILGenerator();
// change list
il.DeclareLocal(typeof(List<Change>));
il.DeclareLocal(typeof(Change));
il.DeclareLocal(typeof(object)); // boxed change
il.Emit(OpCodes.Newobj, typeof(List<Change>).GetConstructor(Type.EmptyTypes));
// [list]
il.Emit(OpCodes.Stloc_0);
foreach (var prop in RelevantProperties())
{
// []
il.Emit(OpCodes.Ldarg_0);
// [original]
il.Emit(OpCodes.Callvirt, prop.GetGetMethod(true));
// [original prop val]
/*****
MAYBE SET ORIGINAL PROP VAL HERE?
*****/
il.Emit(OpCodes.Ldarg_1);
// [original prop val, current]
il.Emit(OpCodes.Callvirt, prop.GetGetMethod(true));
// [original prop val, current prop val]
il.Emit(OpCodes.Dup);
// [original prop val, current prop val, current prop val]
if (prop.PropertyType != typeof(string))
{
il.Emit(OpCodes.Box, prop.PropertyType);
// [original prop val, current prop val, current prop val boxed]
}
il.Emit(OpCodes.Stloc_2);
// [original prop val, current prop val]
il.EmitCall(OpCodes.Call, typeof(Snapshot<T>).GetMethod("AreEqual", BindingFlags.NonPublic | BindingFlags.Static).MakeGenericMethod(new Type[] { prop.PropertyType }), null);
// [result]
Label skip = il.DefineLabel();
il.Emit(OpCodes.Brtrue_S, skip);
// []
il.Emit(OpCodes.Newobj, typeof(Change).GetConstructor(Type.EmptyTypes));
// [change]
il.Emit(OpCodes.Dup);
// [change,change]
il.Emit(OpCodes.Stloc_1);
// [change]
il.Emit(OpCodes.Ldstr, prop.Name);
// [change, name]
il.Emit(OpCodes.Callvirt, typeof(Change).GetMethod("set_Name"));
// []
il.Emit(OpCodes.Ldloc_1);
// [change]
il.Emit(OpCodes.Ldloc_2);
// [change, boxed]
il.Emit(OpCodes.Callvirt, typeof(Change).GetMethod("set_NewValue"));
// []
il.Emit(OpCodes.Ldloc_0);
// [change list]
il.Emit(OpCodes.Ldloc_1);
// [change list, change]
il.Emit(OpCodes.Callvirt, typeof(List<Change>).GetMethod("Add"));
// []
il.MarkLabel(skip);
}
il.Emit(OpCodes.Ldloc_0);
// [change list]
il.Emit(OpCodes.Ret);
return (Func<T, T, List<Change>>)dm.CreateDelegate(typeof(Func<T, T, List<Change>>));
}