【问题标题】:Adding 'OldValue' property to Dapper.Snapshotter.Changes object将“OldValue”属性添加到 Dapper.Snapshotter.Changes 对象
【发布时间】:2018-11-08 19:35:12
【问题描述】:

我们广泛使用 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>>));
                    }

【问题讨论】:

    标签: c# cil


    【解决方案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]
        
        
                            /*
                             * 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>>));
                    }
    

    【讨论】:

      猜你喜欢
      • 2015-09-21
      • 2015-11-15
      • 2021-03-22
      • 2018-07-27
      • 2016-09-25
      • 1970-01-01
      • 2021-09-19
      • 2011-11-23
      相关资源
      最近更新 更多