Tuesday, May 6, 2014

ICloneable not available for Windows Phone 8.

Problem:
I was trying to create a "copy" of an object in memory within .Net framework.  I ran headlong into the stack vs. heap storage.  When I tried to "copy" the parent object to a child object each time I updated the child the parent was also updated.  This is occurring because of the Framework memory management defaults.  The child object is a reference to the parent.  What I need is to clone the object.

Potential Solutions:

Source:
http://www.c-sharpcorner.com/UploadFile/rmcochran/chsarp_memory401152006094206AM/chsarp_memory4.aspx


Sample 1:


using System;

public class IdInfo
{
   public int IdNumber;

   public IdInfo(int IdNumber)
   {
      this.IdNumber = IdNumber;
   }
}

public class Person
{
   public int Age;
   public string Name;
   public IdInfo IdInfo;

   public Person ShallowCopy()
   {
      return (Person)this.MemberwiseClone();
   }

   public Person DeepCopy()
   {
      Person other = (Person)this.MemberwiseClone();
      other.IdInfo = new IdInfo(this.IdInfo.IdNumber);
      return other;
   }
}

public class Example
{
   public static void Demo(System.Windows.Controls.TextBlock outputBlock)
   {
      // Create an instance of Person and assign values to its fields.
      Person p1 = new Person();
      p1.Age = 42;
      p1.Name = "Sam";
      p1.IdInfo = new IdInfo(6565);

      // Perform a shallow copy of p1 and assign it to p2.
      Person p2 = (Person)p1.ShallowCopy();

      // Display values of p1, p2
      outputBlock.Text += "Original values of p1 and p2:" + "\n";
      outputBlock.Text += " p1 instance values: " + "\n";
      DisplayValues(outputBlock, p1);
      outputBlock.Text += " p2 instance values:" + "\n";
      DisplayValues(outputBlock, p2);

      // Change the value of p1 properties and display the values of p1 and p2.
      p1.Age = 32;
      p1.Name = "Frank";
      p1.IdInfo.IdNumber = 7878;
      outputBlock.Text += "\nValues of p1 and p2 after changes to p1:" + "\n";
      outputBlock.Text += " p1 instance values: " + "\n";
      DisplayValues(outputBlock, p1);
      outputBlock.Text += " p2 instance values:" + "\n";
      DisplayValues(outputBlock, p2);

      // Make a deep copy of p1 and assign it to p3.
      Person p3 = p1.DeepCopy();
      // Change the members of the p1 class to new values to show the deep copy.
      p1.Name = "George";
      p1.Age = 39;
      p1.IdInfo.IdNumber = 8641;
      outputBlock.Text += "\nValues of p1 and p3 after changes to p1:" + "\n";
      outputBlock.Text += " p1 instance values: " + "\n";
      DisplayValues(outputBlock, p1);
      outputBlock.Text += " p3 instance values:" + "\n";
      DisplayValues(outputBlock, p3);
   }

   public static void DisplayValues(System.Windows.Controls.TextBlock outputBlock, Person p)
   {
      outputBlock.Text += String.Format(" Name: {0:s}, Age: {1:d}", p.Name, p.Age) + "\n";
      outputBlock.Text += String.Format(" Value: {0:d}", p.IdInfo.IdNumber) + "\n";
   }
}
// The example displays the following output:
// Original values of p1 and p2:
// p1 instance values:
// Name: Sam, Age: 42
// Value: 6565
// p2 instance values:
// Name: Sam, Age: 42
// Value: 6565
//
// Values of p1 and p2 after changes to p1:
// p1 instance values:
// Name: Frank, Age: 32
// Value: 7878
// p2 instance values:
// Name: Sam, Age: 42
// Value: 7878
//
// Values of p1 and p3 after changes to p1:
// p1 instance values:
// Name: George, Age: 39
// Value: 8641
// p3 instance values:
// Name: Frank, Age: 32
// Value: 7878
Source:
http://msdn.microsoft.com/en-us/library/windowsphone/develop/system.object.memberwiseclone(v=vs.105).aspx


Whilst the standard practice is to implement the ICloneable interface (described here, so I won't regurgitate), here's a nice deep clone object copier I found on The Code Project a while ago and incorporated it in our stuff.

using System;
using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;

/// <summary>
/// Reference Article http://www.codeproject.com/KB/tips/SerializedObjectCloner.aspx
/// Provides a method for performing a deep copy of an object.
/// Binary Serialization is used to perform the copy.
/// </summary>
public static class ObjectCopier
{
    /// <summary>
    /// Perform a deep Copy of the object.
    /// </summary>
    /// <typeparam name="T">The type of object being copied.</typeparam>
    /// <param name="source">The object instance to copy.</param>
    /// <returns>The copied object.</returns>
    public static T Clone<T>(T source)
    {
        if (!typeof(T).IsSerializable)
        {
            throw new ArgumentException("The type must be serializable.", "source");
        }

        // Don't serialize a null object, simply return the default for that object
        if (Object.ReferenceEquals(source, null))
        {
            return default(T);
        }

        IFormatter formatter = new BinaryFormatter();
        Stream stream = new MemoryStream();
        using (stream)
        {
            formatter.Serialize(stream, source);
            stream.Seek(0, SeekOrigin.Begin);
            return (T)formatter.Deserialize(stream);
        }
    }
}



Now the method call simply becomes objectBeingCloned.Clone();.

Source:
http://stackoverflow.com/questions/78536/deep-cloning-objects-in-c-sharp

No comments:

Post a Comment