Friday, March 6, 2020

Deep Copy vs Shallow Copy

The past couple of days I have been working on creating a logging service to capture any changes that have been made to our pages. We had a logging service made for another part of our application, but this new portion wouldn't be able to use the old logger. First, the old section that was logging was coded pretty specific to that section of the app. There are a lot of reusable parts, like checking the two objects to see if there are differences, but pieces like adding the differences into a database were very specific. So, I started down adding a method to the AuditLogService that will allow any type of object to go into service and have it logged in the database.

I ran into a problem though. The specific page I was working on was designed to save over the old value instead of creating a new line. I'm not sure why it was programmed this way, but it is what I have to work with. I could redo this part of the program to add a new record in the database and add a flag to show the old record was no longer the correct record, but there was going to be a lot of places to change, and I had all the information I needed in my controller. The old data in the row and all the new data was ready for me to use. All I needed to do was pull what the data currently was on the server, remember data came back, transform and save the new data, and finally run my new service that would find and log all the differences. Should be easy!

The problems all started when my history object kept changing when I would update my new object. What was going on? As I investigated, I determined that the object I was trying to create to remember the history was just a copy of the original object (a shallow copy I would later learn). I tried two ways to copy into the history. First I did a straight copy:

Response originalResponse = responseControllers.GetResponse();
Response historicalResponse = originalResponse;

Exact same copy. And I should have know that. The second method I tried was to go back to the controller and get the object again.

Response originalResponse = responseControllers.GetResponse();
Response historicalResponse = responseControllers.GetResponse();

I did some investigating and I learned that indeed what I was doing was just a direct copy. I should have known, the simple answer is most likely the answer. So, how do you fix it? I had spent a while on this task, so I asked for a little help from my team lead. He mentioned I probably needed to serialize and then deserialize the object again in order to create a deep copy. Well, I created an extension:

    public static class ObjectExtension

    {

        public static T CreateDeepCopy(this T objectToCopy)

        {

            try

            {

                string jsonSerailizedObject = JsonConvert.SerializeObject(objectToCopy);



                return JsonConvert.DeserializeObject(jsonSerailizedObject);

            }

            catch (Exception e)

            {

                Console.WriteLine(e);

                throw;

            }

        }

    }

Now when I change my originalResponse (typing this I realized that original and historical could have been called something different, naming, that hardest part) the historicalReponse no longer changes! Perfect! I am now getting a deep copy, which is a copy of the object and all the references. And I made an extension that we could use again the application, I'm sure we will use it again, right?

I have a console program that I was experimenting with to try and get it to work here


"A true friend never gets in your way unless you happen to be going down." - Arnold H. Glasow