Quoc Nguyen
Quoc Nguyen

Reputation: 360

C# How to remove reference between object when adding to List?

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

Upvotes: 0

Views: 8989

Answers (2)

dbc
dbc

Reputation: 116876

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.

Upvotes: 3

nepdev
nepdev

Reputation: 977

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

Upvotes: 0

Related Questions