Showing posts with label deserialization. Show all posts
Showing posts with label deserialization. Show all posts

Thursday, 4 March 2010

Deep cloning object in C#/.NET

I was asked recently to write a generic method for deep cloning of a complex object. The object contains references to other objects, collections, which contain references to many other objects and collections. The method was supposed to work on both platforms: .NET 3.5 (or higher) and Silverlight.

While googling I found a good post listing different approaches for cloning
C# Object Clone Wars

Last technique described in that blog points to Copyable Framework - generic framework for copying/cloning any objects using method extensions

The framework, written by HÃ¥vard Stranden addresses most of my requirements, except one: it does not work on Silverlight.

I came up with a simple method that serializes the original object and deserializes it to a cloned copy of it. It can be used as an extension or by implementing IClonable interface:

public static class ObjectExtensions
{
  public static T Clone<T>(this object original)
  {
    T cloned;
    using (MemoryStream stream = new MemoryStream())
    {
      DataContractSerializer serializer = new DataContractSerializer(typeof(T));
      serializer.WriteObject(stream, original);
      stream.Position = 0;
      cloned = (T)serializer.ReadObject(stream);
    }
    return cloned;
  }
}


* This source code was highlighted with Source Code Highlighter.

Monday, 15 June 2009

V2: WCF CollectionDataContract and DataMember attributes

Following Jeff's comment on the first version of this post, here are some explanations and a full class.

Q1. Why did I write "implement IEnumerable" twice?
A1. My original intention was to derive my class from ICollection<T>. Thus I had to implement IEnumerable and IEnumerable<T>.

Q2. Why do I bother to implement IEnumerable at all if the class is not "decorated" as IEnumerable?
A2. ICollection<T> "derives" from IEnumerable<T> and IEnumerable, so we have to implement both of them when writing a class that implements ICollection<T>

Here is a complete class:

 [DataContract]
  public class EntityCollectionWorkaround<EntityType> : ICollection<EntityType>
  {
    #region Constructor
    public EntityCollectionWorkaround()
    {
      Entities = new List<EntityType>();
    }
    #endregion

    [DataMember]
    public int AdditionalProperty { get; set; }

    [DataMember]
    public List<EntityType> Entities { get; set; }

    #region ICollection<T> Members

    public void Add(EntityType item)
    {
      Entities.Add(item);
    }

    public void Clear()
    {
      this.Entities.Clear();
    }

    public bool Contains(EntityType item)
    {
      return Entities.Contains(item);
    }

    public void CopyTo(EntityType[] array, int arrayIndex)
    {
      this.Entities.CopyTo(array, arrayIndex);
    }

    public int Count
    {
      get
      {
        return this.Entities.Count;
      }
    }

    public bool IsReadOnly
    {
      get
      {
        return false;
      }
    }

    public bool Remove(EntityType item)
    {
      return this.Entities.Remove(item);
    }

    public EntityType this[int index]
    {
      get
      {
        return this.Entities[index];
      }
      set
      {
        this.Entities[index] = value;
      }
    }
    #endregion

    #region IEnumerable<T> Members

    public IEnumerator<EntityType> GetEnumerator()
    {
      return this.Entities.GetEnumerator();
    }

    #endregion

    #region IEnumerable Members

    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
    {
      return this.Entities.GetEnumerator();
    }

    #endregion
  }


* This source code was highlighted with Source Code Highlighter.

Thursday, 17 July 2008

"The constructor to deserialize an object of type 'MyGenericCollection' was not found."

This exception is thrown by an application that tries to deserialize an instance of MyGenericCollection. In my case it was thrown by BizTalk that stores current state of it variables by their serialization and saving into its database. Then it restores the previous state by deserialization.
MyGenericCollection is a class that derives from Dictionary<Key,value>, which is serializable.

So why the deserialization failed?
Because the deserialization is done within constructor which accepts SerializationInfo and StreamingContext, but constructors are not derived. It means that we need to to define such constructor:

public class MyGenericCollection : Dictionary<Key,Value>
{
protected MyGenericCollection(SerializationInfo info, StreamingContext context)
: base(info, context) { }
}