0

I have a complex object with a lot of Properties with string, decimal and ObservableColection, List...

I want to do this:

foreach (ITransactionItem transactionItem in Transaction.TransactionItemCollection.ToList())
                {                    
                    transactionItem.PickUpQuantity = 0;
                    transactionItem.IsPickUp = false;
                    this.PickUpItemCollection.Add(transactionItem);
                }

The problem is, when I change item in PickUpItemCollection, reference item in TransactionItemCollection is changed too and I don't want it.

I tried to use this ExtensionMethod to Copy object from object:

public static T CopyFrom<T>(this T toObject, object fromObject)
    {
        var fromObjectType = fromObject.GetType();

        foreach (PropertyInfo toProperty in toObject.GetType().GetProperties())
        {
            PropertyInfo fromProperty = fromObjectType.GetProperty(toProperty.Name);

            if (fromProperty != null) // match found
            {
                // check types
                var fromType = Nullable.GetUnderlyingType(fromProperty.PropertyType) ?? fromProperty.PropertyType;
                var toType = Nullable.GetUnderlyingType(toProperty.PropertyType) ?? toProperty.PropertyType;

                if (toType.IsAssignableFrom(fromType)&& toProperty.CanWrite)
                {
                    toProperty.SetValue(toObject, fromProperty.GetValue(fromObject, null), null);
                }
            }
        }

        return toObject;
    }

and implement into this code block as:

foreach (ITransactionItem transactionItem in Transaction.TransactionItemCollection.AsEnumerable().ToList())
                {
                    ITransactionItem transactionItemModel = new TransactionItemModel();
                    transactionItemModel.CopyFrom(transactionItem);

                    transactionItem.PickUpQuantity = 0;
                    transactionItem.IsPickUp = false;
                    this.PickUpItemCollection.Add(transactionItemModel);
                }

But problem is still there, I know I can set property of transactionItemModel as property of transactionItem one by one but there are a lot of properties and it has a lot of List/ObservableCollection too. I think it would be have a better idea for this, right?

Please help me.

Thanks

Quoc Nguyen
  • 348
  • 6
  • 25
  • `CopyFrom` will return a new object, it will not modify the existing object. – Habib Aug 12 '15 at 18:42
  • 3
    `CopyFrom` isn't recursive; if one of the properties on `PickUpItemCollection` is an object and you change that object on the instance created by `CopyFrom`, the original property value will change as well, since both instances of `PickUpItemCollection` will be referencing the same object. – Brian Gradin Aug 12 '15 at 18:45
  • You would need to probably write a new function instead that does stuff like set the ints, string and such to the same value, and created new instances of any class objects with copied values – Keith M Aug 12 '15 at 18:48
  • 1
    Consider cloning with `BinaryFormatter` or Json.NET as in the first answer to this question [Deep cloning objects](http://stackoverflow.com/questions/78536/deep-cloning-objects). – dbc Aug 12 '15 at 18:48
  • For more options, see here: [Faster deep cloning](http://stackoverflow.com/questions/852064/faster-deep-cloning). – dbc Aug 12 '15 at 19:02

2 Answers2

3

Since your source and target are not necessarily of the same type (ITransactionItem and TransactionItemModel respectively) and your target object is pre-allocated, you could (recursively) deep-copy all public properties and fields from the source to the target by serializing to JSON, then populating them in the target with the PopulateObject method of Json.NET:

public static class ObjectExtensions
{
    public static void CopyFrom<TTo, TFrom>(this TTo target, TFrom source) where TTo : class
    {
        if (target == null)
            throw new ArgumentNullException();
        // Preserve object graph structure and handle polymorphic fields.
        var settings = new JsonSerializerSettings { PreserveReferencesHandling = PreserveReferencesHandling.All, ReferenceLoopHandling = ReferenceLoopHandling.Serialize, TypeNameHandling = TypeNameHandling.Auto };
        var json = JsonConvert.SerializeObject(source, settings);
        JsonConvert.PopulateObject(json, target, settings);
    }
}

Most other serializers don't support populating an existing object which is why I suggest this particular method. Deep-copying with BinaryFormatter is a poor choice in this case since it deserializes to a new instance of the exact same type as the serialized type.

dbc
  • 104,963
  • 20
  • 228
  • 340
0

Without knowing your objects, the general answer is - you need to do a deep copy of your object. This isn't as easy as it looks on the surface if the object is complex. See StackOverflow - cloning objects

Community
  • 1
  • 1
nepdev
  • 937
  • 1
  • 11
  • 19