Skip to content

Cloning Object Properties via Reflection

I had a case today where I needed to clone all properties of an object from one class to another of different types.

The originating type was a LINQ 2 SQL entity class type which represents the data model for my database table and the destination object which needed to be cloned to was a custom POCO object which contained all the same property names for streamlined transport over WCF.

I devised a simple function to do the job and it works well to clone all objects aka. properties in an instantiated object by iterating through each property, testing if the same property name can be found and whether the type is the same between originator and destination, if this is the case, the object’s value shall be cloned.

I’ve tested it under an array of different conditions including primitive types, indexers, enum’s and a generic lists of other object type tests, and as you will see by the code there is no type restrictions, so your object should be cloned with no problems generic or custom as long as it adheres to the golden rule of having a matching name and type between origin and destination.

Hopefully this will come in handy for you guys.

I’ve developed it in three flavours; the first being in the all-important Lamda expression syntax (.NET 3.0+):

        ///

        /// Clone properties from an original object to a destination object.
        /// 

        /// 
        /// 
        ///

        ///

        public void CloneProperties(T1 origin, T2 destination)
        {
            // Instantiate if necessary
            if (destination == null) throw new ArgumentNullException("destination", "Destination object must first be instantiated.");
            // Loop through each property in the destination
            foreach (var destinationProperty in destination.GetType().GetProperties())
            {
                // find and set val if we can find a matching property name and matching type in the origin with the origin's value
                if (origin != null && destinationProperty.CanWrite)
                {
                    origin.GetType().GetProperties().Where(x => x.CanRead && (x.Name == destinationProperty.Name && x.PropertyType == destinationProperty.PropertyType))
                        .ToList()
                        .ForEach(x => destinationProperty.SetValue(destination, x.GetValue(origin, null), null));
                }
            }
        }

The second being another lambda (.NET 3.0+) implementation but conveniently wrapped up into an extension method (accessible by originObj.CloneProperties(destObj)):

    public static class ObjectExtension
    {
        ///

        /// Clone properties from an original object to a destination object.
        /// 

        /// 
        /// 
        ///

        ///

        public static void CloneProperties(this T1 origin, T2 destination)
        {
            // Instantiate if necessary
            if (destination == null) throw new ArgumentNullException("destination", "Destination object must first be instantiated.");
            // Loop through each property in the destination
            foreach (var destinationProperty in destination.GetType().GetProperties())
            {
                // find and set val if we can find a matching property name and matching type in the origin with the origin's value
                if (origin != null && destinationProperty.CanWrite)
                {
                    origin.GetType().GetProperties().Where(x => x.CanRead && (x.Name == destinationProperty.Name && x.PropertyType == destinationProperty.PropertyType))
                        .ToList()
                        .ForEach(x => destinationProperty.SetValue(destination, x.GetValue(origin, null), null));
                }
            }
        }
    }

And the more vanilla-flavoured all .NET versions compatible forEach code syntax:

        ///

        /// Clone properties from an original object to a destination object.
        /// 

        /// 
        /// 
        ///

        ///

        public void CloneProperties(T1 origin, T2 destination)
        {
            // Instantiate if necessary
            if (destination == null) throw new ArgumentNullException("destination", "Destination object must first be instantiated.");
            // Loop through each property in the destination
            foreach (var destinationProperty in destination.GetType().GetProperties())
            {
                // find and set val if we can find a matching property name and matching type in the origin with the origin's value
                if (origin != null && destinationProperty.CanWrite)
                {
                    foreach (var originProperty in origin.GetType().GetProperties())
                    {
                        if (destinationProperty.CanWrite && originProperty.CanRead &&
                            (originProperty.Name == destinationProperty.Name && originProperty.PropertyType == destinationProperty.PropertyType))
                        {
                            destinationProperty.SetValue(destination, originProperty.GetValue(origin, null), null);
                        }
                    }
                }
            }
        }

And a complete test case if you’re interested:

        public enum Status
        {
            Active,
            Inactive
        }
        public class Test1
        {
            public string Name { get; set; }
            public decimal Amount { get; set; }
            public bool IsRequired { get; set; }
            public int[] Categories { get; set; }
            public Status Status { get; set; }
            public List StringList { get; set; }
            public List TestInner { get; set; }
        }
        public class Test2
        {
            public string Name { get; set; }
            public decimal Amount { get; set; }
            public bool IsRequired { get; set; }
            public int[] Categories { get; set; }
            public Status Status { get; set; }
            public List StringList { get; set; }
            public List TestInner { get; set; }
        }
        public class TestInner
        {
            public string Name { get; set; }
            public int Value { get; set; }
        }

        public void TestClone()
        {
            // Cloning Test
            // Any properties found to have same name and type will be populated.
            Test1 test1 = new Test1()
            {
                Name = "test",
                Amount = 50.60m,
                IsRequired = true,
                Categories = new[] { 5, 10, 15 },
                Status = Status.Active,
                StringList = new List() { "your", "set", "of", "strings" },
                TestInner = new List()
                                                            {
                                                                new TestInner() { Name = "Test 1 inner #1.", Value = 70 },
                                                                new TestInner() { Name = "Test 1 inner #2.", Value = 80 }
                                                            }
            };

            Test1 testClonedSame = new Test1(); // Instantiation to empty not necessary
            // Test cloning to same object type
            CloneProperties(test1, testClonedSame);

            Test2 testClonedDiff = new Test2(); // Instantiation to empty not necessary
            // Test cloning to different object type
            CloneProperties(test1, testClonedDiff);
            // Or if you're too cool for type arguments...
            // CloneProperties(test1, testClonedDiff);
        }

Enjoy. This should convert to VB.NET if need be with no complications.

VN:F [1.9.10_1130]
Rating: 4.0/5 (4 votes cast)
VN:F [1.9.10_1130]
Rating: 0 (from 0 votes)
Cloning Object Properties via Reflection, 4.0 out of 5 based on 4 ratings
Bookmark and Share
kick it on DotNetKicks.com
Shout it

NOW, FOR A WORD FROM OUR SPONSORS

5 Comments

  1. John Coxhead

    Exctly what I was looking for ! Thanks !

    VA:F [1.9.10_1130]
    Rating: 0.0/5 (0 votes cast)
    VA:F [1.9.10_1130]
    Rating: 0 (from 0 votes)
    Posted on 17-Feb-09 at 1:45 am | Permalink
  2. Graham O'Neale

    No problem!

    VA:F [1.9.10_1130]
    Rating: 0.0/5 (0 votes cast)
    VA:F [1.9.10_1130]
    Rating: 0 (from 0 votes)
    Posted on 17-Feb-09 at 9:18 am | Permalink
  3. Andy

    For a collection type property, it just clone the reference, not a deep clone, so if you add a new item to the cloned collection, the sourcee collection also add a new one, this is what I don’t need, maybe some people also doesn’t need.

    Before read your article, I also write such a methond, the main problem is I can’t deep clone a collection type property.

    VA:F [1.9.10_1130]
    Rating: 5.0/5 (2 votes cast)
    VA:F [1.9.10_1130]
    Rating: 0 (from 2 votes)
    Posted on 09-Sep-09 at 8:50 pm | Permalink
  4. Cool!
    Thanks.

    VA:F [1.9.10_1130]
    Rating: 0.0/5 (0 votes cast)
    VA:F [1.9.10_1130]
    Rating: 0 (from 0 votes)
    Posted on 08-Apr-10 at 5:20 pm | Permalink
  5. here is the code that works in VS 2010 VB.NET:
    Public Module ReflectionExtensions
    ”’
    ”’ Clone properties from an original object to a destination object.
    ”’ See for more info: http://goneale.com/2009/02/16/cloning-object-properties-via-reflection/
    ”’ NOTE: Does not currently handle list’s.
    ”’
    ”’
    ”’
    ”’
    ”’
    _
    Public Sub CloneProperties(Of T1, T2)(ByVal origin As T1, ByVal destination As T2)
    ‘ Instantiate if necessary
    If destination Is Nothing Then
    Throw New ArgumentNullException(“destination”, “Destination object must first be instantiated.”)
    End If
    ‘ Loop through each property in the destination
    For Each destinationProperty As Reflection.PropertyInfo In destination.[GetType]().GetProperties()
    ‘ find and set val if we can find a matching property name and matching type in the origin with the origin’s value
    If origin IsNot Nothing AndAlso destinationProperty.CanWrite Then
    For Each originProperty As Reflection.PropertyInfo In origin.[GetType]().GetProperties()
    If destinationProperty.CanWrite AndAlso originProperty.CanRead AndAlso (originProperty.Name = destinationProperty.Name AndAlso originProperty.PropertyType Is destinationProperty.PropertyType) Then
    destinationProperty.SetValue(destination, originProperty.GetValue(origin, Nothing), Nothing)
    End If
    Next
    End If
    Next

    End Sub
    End Module

    VA:F [1.9.10_1130]
    Rating: 0.0/5 (0 votes cast)
    VA:F [1.9.10_1130]
    Rating: 0 (from 0 votes)
    Posted on 03-Jul-11 at 3:30 pm | Permalink

3 Trackbacks/Pingbacks

  1. [...] Cloning Object Properties via Reflection « {Programming} & Life [...]

  2. [...] Cloning Object Properties via Reflection « {Programming} & Life [...]

  3. DotNetShoutout on 16-Feb-09 at 9:35 pm

    Cloning Object Properties via Reflection « {Programming} & Life…

    Thank you for submitting this cool story – Trackback from DotNetShoutout…

    VA:F [1.9.10_1130]
    Rating: 5.0/5 (1 vote cast)
    VA:F [1.9.10_1130]
    Rating: -1 (from 1 vote)

Post a Comment

Your email is never published nor shared. Required fields are marked *
*
*

My name is Graham O'Neale and I'm a software architect from Gold Coast, Australia. I am an overtime thinker, full time coder and awake part time in the real world. I have a keen interest in software development, particularly in the realm of programming (C#, ASP.NET, ASP.NET MVC, LINQ (2 SQL), Entity Framework, Silverlight, Blend, WCF, WPF) and a keen interest in the cutting edge and innovation. I have a new found love for design patterns, ALT.NET practices and well crafted software architecture. The purpose of this blog is to express any thoughts, findings, tips and gripes along my travels in the wonderful world of coding and technology...