dMilan
dMilan

Reputation: 257

Clone ObservableCollection

I have class with ObservableCollection and other properties. So it looks a little bit like this:

public class A
{
   public int Id { get; set; }
   ...
   public object AValue {get; set;}
}

I would like clone object of this class. AValue property can be ObservableCollection or another object. When AValue is of type ObservableCollection and I trying to add some object to it it's seems that clone have the same object that orginal. If I use my clone method only to AValue Property, not to object of class A it works. To clone objects I tried to use:

 private object Clone(object obj)
    {
        var t = obj.GetType();

        if (obj == null)
            return null;

        if (t.IsValueType || t == typeof(string))
        {
            return obj;
        }
        else if (t.IsGenericType)
        {
            if (obj is IList)
            {
                var c= typeof(ObservableCollection<>);
                var cType = type.GetGenericArguments().First();
                var gType = c.MakeGenericType(cType);
                var newC = (IList)Activator.CreateInstance(gType);

                foreach (var item in (IEnumerable)obj)
                    newC.Add(item);

                return newC;
            }
        }
        else if (t.IsClass)
        {
            object objV = Activator.CreateInstance(type);
            FieldInfo[] fields = t.GetFields(BindingFlags.Public |
                        BindingFlags.NonPublic | BindingFlags.Instance);
            foreach (FieldInfo field in fields)
            {
                object fieldV = field.GetValue(obj);
                if (fieldValue == null)
                    continue;
                field.SetValue(objV, Clone(fieldV));
            }
            return obj;
        }
        throw new ArgumentException("Unknown type");
    }
}

Edit thanks for answer. I added your code @Sefe but it still doesn't works. I know that other types doesn't clone but I would like to do it with lists first. I don't known where is mistake. I get the A class object then I clone object and send A class object to dialogbox. I change collection and properties from clone and orginal are the same. It's enought to add IClonable interface to generic type of list

 ObservableCollection<B> = new  ObservableCollection<B>();

public class B: Base, ICloneable
{
  ...
  public object Clone()
  {
    return this.MemberwiseClone();
  }

}

Is it important that generic type can inherit from another class?

Upvotes: 2

Views: 10414

Answers (1)

Sefe
Sefe

Reputation: 14007

You are cloning the collection, but you are not cloning its items. To create a deep clone of the collection, you need to also clone the items (if possible):

foreach (var item in (IEnumerable)obj) {
    ICloneable cloneable = item as ICloneable;
    if (cloneable != null) {
        newC.Add(cloneable.Clone());
    }
    else {
        newC.Add(item);
    }
}

Using the ICloneable interface is the built-in way in the .NET framework and you can expect framweork methods to recognize it where necessary. So this would be the preferred way. If you want to reuse your own existing Clone method instead, you can call it recursively:

foreach (var item in (IEnumerable)obj) {
    newC.Add(Clone(item));
}

UPDATE (To adress the question's edit):

When you use MemberwiseClone, all fields and events will be transferred to the clone. MemberwiseClone creates a shallow copy, so the fields and assigned event handlers are transferred. So if you have fields that contain other reference types, these will be not cloned (even if they are ICloneable). Also, event handlers that are assigned to the orginal, will also be assigned to the clone.

Your ICloneable.Clone method will have to take care to put the clone in a valid state. Because what is valid differs from case to case, there is no automatic deep cloning in the .NET framework. Invoking MemberwiseClone is usually a good start, but you have to then adress contained objects, event handlers etc. to "upgrade" your shallow clone to a deep clone.

Upvotes: 5

Related Questions