Aug 192010
 

Recently, I was working on a project when I came into a problem that I hadn’t dealt with before.  You see I was working with a rather large table (200+ fields) and a corresponding archive table for it.  The goal was to be able to populate a form with fields from either of the object types as essentially they were the same record type.
We were using LINQ to SQL objects and when I wrote the method that populates the form I had it taking in the base object.  Well then I was given instruction to be able to load the archive records into the form as well and I had to decide the best approach.

The simplest solution was to write a copy of the method that populated the form and have it take in the archive table object, but I did not like that solution as it added an additional point where code would need to be updated if fields were added or removed.

Another solution that I came across during my search was to add a specific conversion method to the definition of the linq object.  Aside from some technical difficulties that would have still left me with a similar situation as above where if fields were added or removed it would be another spot in code that would have to be modified.

Finally it occurred to me to use reflection to set the properties of one object from the properties of another.  Then it became a task to write a generic method that would not only handle my two LINQ objects in this situation but nearly any two similar objects that I wanted to convert. Below is the code that resulted.

protected T ConvertToObject<T>(object InputObject, ref T OutputObject)
{
    Type InputType = InputObject.GetType();
    Type OutputType = typeof(T);

    System.Reflection.PropertyInfo[] piInput = InputType.GetProperties();
    System.Reflection.PropertyInfo[] piOutput = OutputType.GetProperties();
    foreach (System.Reflection.PropertyInfo piOutProperty in piOutput)
    {
        foreach (System.Reflection.PropertyInfo piInputProperty in piInput)
        {
            if (piOutProperty.Name == piInputProperty.Name
                && piOutProperty.PropertyType == piInputProperty.PropertyType)
            {
                piOutProperty.SetValue(OutputObject, piInputProperty.GetValue(InputObject, null), null);
            }
        }
    }
    return OutputObject;
}

The above method will allow you to easily cast from one object type to another.  As you can see there is one type parameter which is the return or output object type.  Then you pass in two objects, the object you are pulling the values from and then an instantiated object that you will be passing the values into.  Notice that the second parameter is also passed in by reference, this will allow you to not have to have any type parameter or have a return object.

My method go through both collections of properties for the two object types and looks for a match based on name and type.  Another way of doing things is just going through the properties of the input object and trying to force them into the output object and catching and discarding any errors that occur.  You can see an example of that below.

protected T ConvertToObject<T>(object InputObject, ref T OutputObject)
{
    Type InputType = InputObject.GetType();

    foreach (System.Reflection.PropertyInfo piInputProperty in InputType.GetProperties())
    {
        try
        {
            piInputProperty.SetValue(OutputObject, piInputProperty.GetValue(InputObject, null), null);
        }
        catch { }
    }
    return OutputObject;
}

It should also be noted that depending on the objects you need to convert you may need to loop through the fields collection as well and set those.  I found that in my case all that I needed to set were the properties so that was all I worried about.

So in conclusion when you have the need to quickly convert one object type to another it’s easiest just to use reflection to get it done.

  4 Responses to “Converting a Linq Object to a Similar Object”

  1. Congrlatulations!
    You invented AutoMapper!
    http://automapper.codeplex.com/

  2. How’s the performance of this versus your first approach?

  3. found your site on del.icio.us today and really liked it.. i bookmarked it and will be back to check it out some more later

 Leave a Reply

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

This site uses Akismet to reduce spam. Learn how your comment data is processed.