Adding 'OldValue' property to Dapper.Snapshotter.Changes object











up vote
1
down vote

favorite












We use Dapper's Snapshotter extensively so identify property changes to make updates more efficient. We're now looking to use it to identify changes that could be used for logging. In order to do this, we need to add the property OldValue to the nested class Changes (which has Name and NewValue).



All the information is there in this class, but it uses the Emit library. I've tried various line additions trying to access that original property's value and set it to OldValue:



e.g.
il.Emit(OpCodes.Callvirt, typeof(Change).GetMethod("set_OldValue"));



However, I keep getting errors saying that it destabilizes the runtime. I like to tinker, but the Emit library is very new ground. I was hoping someone (...https://stackoverflow.com/users/23354/marc-gravell...https://stackoverflow.com/users/13249/nick-craver) with expertise could guide me here.



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









share|improve this question




























    up vote
    1
    down vote

    favorite












    We use Dapper's Snapshotter extensively so identify property changes to make updates more efficient. We're now looking to use it to identify changes that could be used for logging. In order to do this, we need to add the property OldValue to the nested class Changes (which has Name and NewValue).



    All the information is there in this class, but it uses the Emit library. I've tried various line additions trying to access that original property's value and set it to OldValue:



    e.g.
    il.Emit(OpCodes.Callvirt, typeof(Change).GetMethod("set_OldValue"));



    However, I keep getting errors saying that it destabilizes the runtime. I like to tinker, but the Emit library is very new ground. I was hoping someone (...https://stackoverflow.com/users/23354/marc-gravell...https://stackoverflow.com/users/13249/nick-craver) with expertise could guide me here.



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









    share|improve this question


























      up vote
      1
      down vote

      favorite









      up vote
      1
      down vote

      favorite











      We use Dapper's Snapshotter extensively so identify property changes to make updates more efficient. We're now looking to use it to identify changes that could be used for logging. In order to do this, we need to add the property OldValue to the nested class Changes (which has Name and NewValue).



      All the information is there in this class, but it uses the Emit library. I've tried various line additions trying to access that original property's value and set it to OldValue:



      e.g.
      il.Emit(OpCodes.Callvirt, typeof(Change).GetMethod("set_OldValue"));



      However, I keep getting errors saying that it destabilizes the runtime. I like to tinker, but the Emit library is very new ground. I was hoping someone (...https://stackoverflow.com/users/23354/marc-gravell...https://stackoverflow.com/users/13249/nick-craver) with expertise could guide me here.



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









      share|improve this question















      We use Dapper's Snapshotter extensively so identify property changes to make updates more efficient. We're now looking to use it to identify changes that could be used for logging. In order to do this, we need to add the property OldValue to the nested class Changes (which has Name and NewValue).



      All the information is there in this class, but it uses the Emit library. I've tried various line additions trying to access that original property's value and set it to OldValue:



      e.g.
      il.Emit(OpCodes.Callvirt, typeof(Change).GetMethod("set_OldValue"));



      However, I keep getting errors saying that it destabilizes the runtime. I like to tinker, but the Emit library is very new ground. I was hoping someone (...https://stackoverflow.com/users/23354/marc-gravell...https://stackoverflow.com/users/13249/nick-craver) with expertise could guide me here.



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






      dapper dapper-extensions dapper-rainbow






      share|improve this question















      share|improve this question













      share|improve this question




      share|improve this question








      edited Nov 9 at 12:40

























      asked Nov 8 at 19:35









      BlackjacketMack

      3,6712024




      3,6712024
























          1 Answer
          1






          active

          oldest

          votes

















          up vote
          1
          down vote













          This does it! After adding the OldValue to Changes, Basically, declare a new local variable and push retrieve the value and pop it into that local 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>>));
          }





          share|improve this answer





















            Your Answer






            StackExchange.ifUsing("editor", function () {
            StackExchange.using("externalEditor", function () {
            StackExchange.using("snippets", function () {
            StackExchange.snippets.init();
            });
            });
            }, "code-snippets");

            StackExchange.ready(function() {
            var channelOptions = {
            tags: "".split(" "),
            id: "1"
            };
            initTagRenderer("".split(" "), "".split(" "), channelOptions);

            StackExchange.using("externalEditor", function() {
            // Have to fire editor after snippets, if snippets enabled
            if (StackExchange.settings.snippets.snippetsEnabled) {
            StackExchange.using("snippets", function() {
            createEditor();
            });
            }
            else {
            createEditor();
            }
            });

            function createEditor() {
            StackExchange.prepareEditor({
            heartbeatType: 'answer',
            convertImagesToLinks: true,
            noModals: true,
            showLowRepImageUploadWarning: true,
            reputationToPostImages: 10,
            bindNavPrevention: true,
            postfix: "",
            imageUploader: {
            brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
            contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
            allowUrls: true
            },
            onDemand: true,
            discardSelector: ".discard-answer"
            ,immediatelyShowMarkdownHelp:true
            });


            }
            });














             

            draft saved


            draft discarded


















            StackExchange.ready(
            function () {
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53214934%2fadding-oldvalue-property-to-dapper-snapshotter-changes-object%23new-answer', 'question_page');
            }
            );

            Post as a guest















            Required, but never shown

























            1 Answer
            1






            active

            oldest

            votes








            1 Answer
            1






            active

            oldest

            votes









            active

            oldest

            votes






            active

            oldest

            votes








            up vote
            1
            down vote













            This does it! After adding the OldValue to Changes, Basically, declare a new local variable and push retrieve the value and pop it into that local 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>>));
            }





            share|improve this answer

























              up vote
              1
              down vote













              This does it! After adding the OldValue to Changes, Basically, declare a new local variable and push retrieve the value and pop it into that local 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>>));
              }





              share|improve this answer























                up vote
                1
                down vote










                up vote
                1
                down vote









                This does it! After adding the OldValue to Changes, Basically, declare a new local variable and push retrieve the value and pop it into that local 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>>));
                }





                share|improve this answer












                This does it! After adding the OldValue to Changes, Basically, declare a new local variable and push retrieve the value and pop it into that local 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>>));
                }






                share|improve this answer












                share|improve this answer



                share|improve this answer










                answered Nov 9 at 14:48









                BlackjacketMack

                3,6712024




                3,6712024






























                     

                    draft saved


                    draft discarded



















































                     


                    draft saved


                    draft discarded














                    StackExchange.ready(
                    function () {
                    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53214934%2fadding-oldvalue-property-to-dapper-snapshotter-changes-object%23new-answer', 'question_page');
                    }
                    );

                    Post as a guest















                    Required, but never shown





















































                    Required, but never shown














                    Required, but never shown












                    Required, but never shown







                    Required, but never shown

































                    Required, but never shown














                    Required, but never shown












                    Required, but never shown







                    Required, but never shown







                    Popular posts from this blog

                    Schultheiß

                    Verwaltungsgliederung Dänemarks

                    Liste der Kulturdenkmale in Wilsdruff