views:

66

answers:

1

I have a method where I am passing in two object, which have the same property names, and I'm using Reflection to get the values from one object and set the values on the other. My problem is when I come across a property that is a collection, the original is EntityCollection and the one getting set is ObservableCollection, and I'm obviously going to throw a casting error when I try to set the value.

So how would I go about this? I thought one way would be to get the instance of the EntityCollection property and in a loop use Activator.CreateInstance() to add a new item to the ObservableCollection. But I come across another question of how to get the original instance.

I would be greatly appreciative for some insight into this dilemma. I'll post the code for the method that I'm working with. It currently doesn't work, mainly I posted it just for a reference. So please don't point out the obvious. Thanks in advance.

protected void SetValues(Object thisObject, Object entity)
{
    PropertyInfo[] properties = entity.GetType().GetProperties();
    foreach (PropertyInfo property in properties)
    {
        var value = property.GetValue(entity, null);
        var thisObjectsProperty = thisObject.GetType().GetProperty(property.Name);

        if (thisObjectsProperty != null && value != null)
        {
            if (thisObjectsProperty.PropertyType.GetInterface("ICollection", true) != null                && thisObjectsProperty.PropertyType.GetGenericArguments().Count() > 0)
            {
                Type genericType = thisObjectsProperty.PropertyType.GetGenericArguments()[0];
                Type entityCollectionType = property.PropertyType;
                Type thisCollectionType = thisObjectsProperty.PropertyType;

                IList entityCollection = (IList)Activator.CreateInstance(entityCollectionType.MakeGenericType(genericType));
                IList observableCollection = (IList)Activator.CreateInstance(thisCollectionType.MakeGenericType(genericType));

                foreach (var item in entityCollection)
                {
                    String typeString = String.Concat("RulesGenerator.DependencyObjects.", genericType.Name);
                    Type newItemType = Type.GetType(typeString, false, true);
                    if (newItemType != null)
                    {
                        var newItem = Activator.CreateInstance(newItemType);
                        SetValues(newItem, item);
                        observableCollection.Add(newItem);
                    }
                }
            }
            else
                thisObjectsProperty.SetValue(thisObject, value, null);
        }
    }
}
A: 

Implement the ICloneable interface to provide a deep copy. You should be able to find some examples, but here is a starting point:

http://msdn.microsoft.com/en-us/library/system.icloneable%28v=VS.71%29.aspx

http://en.csharp-online.net/ICloneable

using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Diagnostics;


public class testMain : ICloneable
{

    private string m_TestProp;

    private List<Record> m_Items = new List<Record>();
    public string TestProp
    {
        get { return m_TestProp; }
        set { m_TestProp = value; }
    }

    public List<Record> Items
    {
        get { return m_Items; }
    }


    public object Clone()
    {

        testMain cpy =(testMain) this.MemberwiseClone();

        foreach (Record rec in this.Items)
        {
            Record recCpy = (Record)rec.Clone();
            cpy.Items.Add(recCpy);
        }

        return cpy;
    }

}

public class Record : ICloneable
{

    private string m_TestProp;

    public string TestProp
    {
        get { return m_TestProp; }
        set { m_TestProp = value; }
    }

    public object Clone()
    {
        return this.MemberwiseClone();
    }
}
eschneider
After looking at it, when I call the GetValue method of the PropertyInfo instance, it gives me an instance of the EntityCollection. Problem is that GetValue returns an Object type. So now my question is, how do you cast an object to EntityCollection<T> when the generic parameter T will need to be set dynamically. Something like..., Type genericEntityType = property.PropertyType.GetGenericArguments()[0]; var ec = property.GetValue() as EntityCollection<genericEntityType>;
jhorton
ICloneable is a better approach..
eschneider
It's not that your approach can't work (it can), just this is a common way to copy objects and easier to maintain.
eschneider
Yeah, I can see the benefits in cloning. But I still have the issue with casting, or maybe I'm missing something. But in your Clone method you have "Record recCpy = (Record)rec.Clone();" where you are casting the clone to a Record type. This is where I can't seem to get past, because I need to be able to cast to an EntityCollection<> but the typename is unknown. I can get the Type from GetGenericArguments(), but I cant use a variable to set the typename. Guess it would be something like dynamic casting.
jhorton
Ok, so I have to add that I'm also using a Silverlight application and am working on a class that is a DependencyObject. And for some reason ICloneable interface is not available in Silverlight applications. The MSDN has an article that explains why, but I haven't read it yet. Only thing that mattered to my current situation is that it's not available.
jhorton
You could try casting the collection to ICollection, IEnumerable or IList, looks like you only need the items not the collection.
eschneider