Добавление свойства OldValue к объекту Dapper.Snapshotter.Changes

Мы широко используем моментальный снимок Dapper, поэтому выявляем изменения свойств, чтобы сделать обновления более эффективными. Сейчас мы хотим использовать его для определения изменений, которые могут быть использованы для регистрации. Для этого нам нужно добавить свойство OldValue к вложенному классу Changes (у которого есть Name а также NewValue).

В этом классе есть вся информация, но она использует библиотеку Emit. Я пробовал различные добавления строк, пытаясь получить доступ к значению этого исходного свойства и установить его OldValue:

напримерil.Emit(OpCodes.Callvirt, typeof(Change).GetMethod("set_OldValue"));

Тем не менее, я продолжаю получать сообщения о том, что это дестабилизирует среду выполнения. Мне нравится возиться, но библиотека Emit - это совершенно новая почва. Я надеялся, что кто-то (... Marc Gravell) может направить меня сюда.

     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>>));
                    }

1 ответ

Это делает это! После добавления OldValue в Changes, в основном, объявляют новую локальную переменную и нажимают, извлекают значение и вставляют его в эту локальную переменную.

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 new value
                    il.DeclareLocal(typeof(object)); // RM - boxed old value

                    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]


                        /*
                         * RM - We're going to dupe and store the old value into loc3.
                         */

                        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_3);
                        // [original prop val, current prop val]

                        /*
                         * 
                         */



                        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"));
                        // []

                        /*
                         * Begin setting value
                         */

                        il.Emit(OpCodes.Ldloc_1);
                        // [change]

                        il.Emit(OpCodes.Ldloc_3);
                        // [change, boxed]

                        il.Emit(OpCodes.Callvirt, typeof(Change).GetMethod("set_OldValue"));
                        // []

                        /*
                         * End Playground
                         */

                        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>>));
                }
Другие вопросы по тегам