将'OldValue'属性添加到Dapper.Snapshotter.Changes对象

时间:2018-11-08 19:35:13

标签: dapper dapper-extensions dapper-rainbow

我们广泛使用Dapper的Snapshotter,以便识别属性更改以使更新更有效。我们现在正在寻找使用它来识别可用于日志记录的更改。为此,我们需要将属性OldValue添加到嵌套类Changes(具有NameNewValue)中。

所有信息都在此类中,但是它使用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 :(得分:1)

做到了!在将OldValue添加到Changes之后,基本上,声明一个新的局部变量,并推动检索该值并将其弹出到该局部var中。

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