代码之家  ›  专栏  ›  技术社区  ›  BlackjacketMack

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

  •  1
  • BlackjacketMack  · 技术社区  · 6 年前

    OldValue Changes (其中 Name NewValue ).

    :

    例如 il.Emit(OpCodes.Callvirt, typeof(Change).GetMethod("set_OldValue"));

    但是,我不断收到错误,说它破坏了运行时的稳定性。我喜欢修补,但发射库是一个非常新的领域。我希望有人(。。。 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 回复  |  直到 4 年前
        1
  •  1
  •   BlackjacketMack    6 年前

    就这样!在将OldValue添加到Changes之后,基本上,声明一个新的局部变量,然后push检索该值并将其弹出到该局部变量中。

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