Добавление свойства OldValue к объекту Dapper.Snapshotter.Changes - PullRequest
0 голосов
/ 08 ноября 2018

Мы широко используем 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>>));
                    }

1 Ответ

0 голосов
/ 09 ноября 2018

Это делает это! После добавления 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>>));
                }
...