108

Given 2 objects A and B of type T, I want to assign the properties' values in A to the same properties in B without doing an explicit assignment for each property.

I want to save code like this:

b.Nombre = a.Nombre;
b.Descripcion = a.Descripcion;
b.Imagen = a.Imagen;
b.Activo = a.Activo;

doing something like

a.ApplyProperties(b);

Is it possible?

Mark Amery
  • 143,130
  • 81
  • 406
  • 459
eKek0
  • 23,005
  • 25
  • 91
  • 119
  • Is there a solution which is not using Reflection? – Tharindu Sathischandra Apr 29 '20 at 05:52
  • @TharinduSathischandra - No. The closest functionality that exists is `MemberwiseClone`, however that always creates a new object; there is no way to generally overwrite all properties in an existing object. (Also read about caveats with MemberwiseClone, before using it.) – ToolmakerSteve Mar 12 '21 at 02:40

16 Answers16

111

Because I believe Jon's version is a tad too complicated and and Steve's version is too simple, and I like Daniel's idea of an extension class.

Plus a Generic version is pretty but unnecessary as all items are objects.

I would like to volunteer my lean and mean version. Credits to all the above. :D

Code:

using System;
using System.Reflection;
/// <summary>
/// A static class for reflection type functions
/// </summary>
public static class Reflection
{
    /// <summary>
    /// Extension for 'Object' that copies the properties to a destination object.
    /// </summary>
    /// <param name="source">The source.</param>
    /// <param name="destination">The destination.</param>
    public static void CopyProperties(this object source, object destination)
    {
        // If any this null throw an exception
        if (source == null || destination == null)
            throw new Exception("Source or/and Destination Objects are null");
            // Getting the Types of the objects
        Type typeDest = destination.GetType();
        Type typeSrc = source.GetType();

        // Iterate the Properties of the source instance and  
        // populate them from their desination counterparts  
        PropertyInfo[] srcProps = typeSrc.GetProperties();
        foreach (PropertyInfo srcProp in srcProps)
        {
            if (!srcProp.CanRead)
            {
                continue;
            }
            PropertyInfo targetProperty = typeDest.GetProperty(srcProp.Name);
            if (targetProperty == null)
            {
                continue;
            }
            if (!targetProperty.CanWrite)
            {
                continue;
            }
            if (targetProperty.GetSetMethod(true) != null && targetProperty.GetSetMethod(true).IsPrivate)
            {
                continue;
            }
            if ((targetProperty.GetSetMethod().Attributes & MethodAttributes.Static) != 0)
            {
                continue;
            }
            if (!targetProperty.PropertyType.IsAssignableFrom(srcProp.PropertyType))
            {
                continue;
            }
            // Passed all tests, lets set the value
            targetProperty.SetValue(destination, srcProp.GetValue(source, null), null);
        }
    }
}

Usage:

/// <summary>
/// ExampleCopyObject
/// </summary>
/// <returns></returns>
public object ExampleCopyObject()
{
    object destObject = new object();
    this.CopyProperties(destObject); // inside a class you want to copy from

    Reflection.CopyProperties(this, destObject); // Same as above but directly calling the function

    TestClass srcClass = new TestClass();
    TestStruct destStruct = new TestStruct();
    srcClass.CopyProperties(destStruct); // using the extension directly on a object

    Reflection.CopyProperties(srcClass, destObject); // Same as above but directly calling the function

    //so on and so forth.... your imagination is the limits :D
    return srcClass;
}

public class TestClass
{
    public string Blah { get; set; }
}
public struct TestStruct
{
    public string Blah { get; set; }
}

As I was bored and a linq version was suggested by a comment

using System;
using System.Linq;
using System.Reflection;
/// <summary>
/// A static class for reflection type functions
/// </summary>
public static class Reflection
{
    /// <summary>
    /// Extension for 'Object' that copies the properties to a destination object.
    /// </summary>
    /// <param name="source">The source.</param>
    /// <param name="destination">The destination.</param>
    public static void CopyProperties(this object source, object destination)
    {
        // If any this null throw an exception
        if (source == null || destination == null)
            throw new Exception("Source or/and Destination Objects are null");
        // Getting the Types of the objects
        Type typeDest = destination.GetType();
        Type typeSrc = source.GetType();
        // Collect all the valid properties to map
        var results = from srcProp in typeSrc.GetProperties()
                                    let targetProperty = typeDest.GetProperty(srcProp.Name)
                                    where srcProp.CanRead
                                    && targetProperty != null
                                    && (targetProperty.GetSetMethod(true) != null && !targetProperty.GetSetMethod(true).IsPrivate)
                                    && (targetProperty.GetSetMethod().Attributes & MethodAttributes.Static) == 0
                                    && targetProperty.PropertyType.IsAssignableFrom(srcProp.PropertyType)
                                    select new { sourceProperty = srcProp, targetProperty = targetProperty };
        //map the properties
        foreach (var props in results)
        {
            props.targetProperty.SetValue(destination, props.sourceProperty.GetValue(source, null), null);
        }
    }
}
Mark Amery
  • 143,130
  • 81
  • 406
  • 459
Azerothian
  • 386
  • 1
  • 6
  • 9
  • Haha, I was literally thinking this same thought to myself when I scrolled down to your answer. The Goldilocks solution. Although, if I was to write one it would definitely use Linq :) – theMayer Dec 13 '13 at 22:02
  • I'm getting a null exception. I think it have something to do with a read-only property. How can I avoid that? – Pedro77 Jun 22 '14 at 22:08
  • Ok, solved it adding just after where: "(targetProperty.GetSetMethod(true) != null && !targetProperty.GetSetMethod(true).IsPrivate)" – Pedro77 Jun 22 '14 at 22:42
  • 32
    There should be a badge for answers that have 20 votes on a question that Jon Skeet also answered. – Tony L. May 13 '15 at 04:21
  • Why the "!targetProperty.GetSetMethod(true).IsPrivate"? – Rhyous Nov 10 '16 at 23:56
  • You are unable to set private properties from outside the object. – Azerothian Nov 11 '16 at 03:19
  • Linq method using foreach()??? You can also write it in linq. results.ForEach(x => x.targetProperty.SetValue( ... – Pa0l0 Aug 24 '17 at 12:50
  • I love simplicity. Worked perfectly. Thanks! – Marquez Nov 20 '19 at 15:21
  • 3
    I have posted an answer with an adapted version, i needed a few extra features. I wanted a way to ignore certain properties, ignore null properties and have an option to coerce data types where possible (e.g. int vs long). – Justin May 13 '20 at 13:54
  • Quick note - Roslyn doesn't like the LINQ version, complaining about "dereference of a possibly null value". It's an easy fix, but per the CC-BY-SA license this is apparently under, I'm sharing the modifications I've made here: https://pastebin.com/J7V6LG3X – Tam Coton Sep 07 '22 at 08:33
80

I have a type in MiscUtil called PropertyCopy which does something similar - although it creates a new instance of the target type and copies the properties into that.

It doesn't require the types to be the same - it just copies all the readable properties from the "source" type to the "target" type. Of course if the types are the same, that's more likely to work :) It's a shallow copy, btw.

In the code block at the bottom of this answer, I've extended the capabilities of the class. To copy from one instance to another, it uses simple PropertyInfo values at execution time - this is slower than using an expression tree, but the alternative would be to write a dynamic method, which I'm not too hot on. If performance is absolutely critical for you, let me know and I'll see what I can do. To use the method, write something like:

MyType instance1 = new MyType();
// Do stuff
MyType instance2 = new MyType();
// Do stuff

PropertyCopy.Copy(instance1, instance2);

(where Copy is a generic method called using type inference).

I'm not really ready to do a full MiscUtil release, but here's the updated code, including comments. I'm not going to rewrap them for the SO editor - just copy the whole chunk.

(I'd also probably redesign the API a bit in terms of naming if I were starting from scratch, but I don't want to break existing users...)

#if DOTNET35
using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Reflection;

namespace MiscUtil.Reflection
{
    /// <summary>
    /// Non-generic class allowing properties to be copied from one instance
    /// to another existing instance of a potentially different type.
    /// </summary>
    public static class PropertyCopy
    {
        /// <summary>
        /// Copies all public, readable properties from the source object to the
        /// target. The target type does not have to have a parameterless constructor,
        /// as no new instance needs to be created.
        /// </summary>
        /// <remarks>Only the properties of the source and target types themselves
        /// are taken into account, regardless of the actual types of the arguments.</remarks>
        /// <typeparam name="TSource">Type of the source</typeparam>
        /// <typeparam name="TTarget">Type of the target</typeparam>
        /// <param name="source">Source to copy properties from</param>
        /// <param name="target">Target to copy properties to</param>
        public static void Copy<TSource, TTarget>(TSource source, TTarget target)
            where TSource : class
            where TTarget : class
        {
            PropertyCopier<TSource, TTarget>.Copy(source, target);
        }
    }

    /// <summary>
    /// Generic class which copies to its target type from a source
    /// type specified in the Copy method. The types are specified
    /// separately to take advantage of type inference on generic
    /// method arguments.
    /// </summary>
    public static class PropertyCopy<TTarget> where TTarget : class, new()
    {
        /// <summary>
        /// Copies all readable properties from the source to a new instance
        /// of TTarget.
        /// </summary>
        public static TTarget CopyFrom<TSource>(TSource source) where TSource : class
        {
            return PropertyCopier<TSource, TTarget>.Copy(source);
        }
    }

    /// <summary>
    /// Static class to efficiently store the compiled delegate which can
    /// do the copying. We need a bit of work to ensure that exceptions are
    /// appropriately propagated, as the exception is generated at type initialization
    /// time, but we wish it to be thrown as an ArgumentException.
    /// Note that this type we do not have a constructor constraint on TTarget, because
    /// we only use the constructor when we use the form which creates a new instance.
    /// </summary>
    internal static class PropertyCopier<TSource, TTarget>
    {
        /// <summary>
        /// Delegate to create a new instance of the target type given an instance of the
        /// source type. This is a single delegate from an expression tree.
        /// </summary>
        private static readonly Func<TSource, TTarget> creator;

        /// <summary>
        /// List of properties to grab values from. The corresponding targetProperties 
        /// list contains the same properties in the target type. Unfortunately we can't
        /// use expression trees to do this, because we basically need a sequence of statements.
        /// We could build a DynamicMethod, but that's significantly more work :) Please mail
        /// me if you really need this...
        /// </summary>
        private static readonly List<PropertyInfo> sourceProperties = new List<PropertyInfo>();
        private static readonly List<PropertyInfo> targetProperties = new List<PropertyInfo>();
        private static readonly Exception initializationException;

        internal static TTarget Copy(TSource source)
        {
            if (initializationException != null)
            {
                throw initializationException;
            }
            if (source == null)
            {
                throw new ArgumentNullException("source");
            }
            return creator(source);
        }

        internal static void Copy(TSource source, TTarget target)
        {
            if (initializationException != null)
            {
                throw initializationException;
            }
            if (source == null)
            {
                throw new ArgumentNullException("source");
            }
            for (int i = 0; i < sourceProperties.Count; i++)
            {
                targetProperties[i].SetValue(target, sourceProperties[i].GetValue(source, null), null);
            }

        }

        static PropertyCopier()
        {
            try
            {
                creator = BuildCreator();
                initializationException = null;
            }
            catch (Exception e)
            {
                creator = null;
                initializationException = e;
            }
        }

        private static Func<TSource, TTarget> BuildCreator()
        {
            ParameterExpression sourceParameter = Expression.Parameter(typeof(TSource), "source");
            var bindings = new List<MemberBinding>();
            foreach (PropertyInfo sourceProperty in typeof(TSource).GetProperties(BindingFlags.Public | BindingFlags.Instance))
            {
                if (!sourceProperty.CanRead)
                {
                    continue;
                }
                PropertyInfo targetProperty = typeof(TTarget).GetProperty(sourceProperty.Name);
                if (targetProperty == null)
                {
                    throw new ArgumentException("Property " + sourceProperty.Name + " is not present and accessible in " + typeof(TTarget).FullName);
                }
                if (!targetProperty.CanWrite)
                {
                    throw new ArgumentException("Property " + sourceProperty.Name + " is not writable in " + typeof(TTarget).FullName);
                }
                if ((targetProperty.GetSetMethod().Attributes & MethodAttributes.Static) != 0)
                {
                    throw new ArgumentException("Property " + sourceProperty.Name + " is static in " + typeof(TTarget).FullName);
                }
                if (!targetProperty.PropertyType.IsAssignableFrom(sourceProperty.PropertyType))
                {
                    throw new ArgumentException("Property " + sourceProperty.Name + " has an incompatible type in " + typeof(TTarget).FullName);
                }
                bindings.Add(Expression.Bind(targetProperty, Expression.Property(sourceParameter, sourceProperty)));
                sourceProperties.Add(sourceProperty);
                targetProperties.Add(targetProperty);
            }
            Expression initializer = Expression.MemberInit(Expression.New(typeof(TTarget)), bindings);
            return Expression.Lambda<Func<TSource, TTarget>>(initializer, sourceParameter).Compile();
        }
    }
}
#endif
Mark Amery
  • 143,130
  • 81
  • 406
  • 459
Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • This fails when copying to an existing target if the target doesn't have it's own constructor, e.g. IMyType instance2 = new MyType(); Is this unavoidable? – stovroz Jan 29 '10 at 20:04
  • @stovroz: Well, you'd have to supply the type that you actually wanted to instantiate. – Jon Skeet Jan 29 '10 at 20:20
  • @Jon: But the target is already instantiated. I thought your above enhancements were precisely to allow copying to an existing target, but it seems to want to create a new one anyway at: Expression.MemberInit(Expression.New(typeof(TTarget)), bindings). – stovroz Jan 29 '10 at 21:21
  • @Jon: I have class that contains List<> properties, but it does not creates new instance of List<>, so if I add something to list it will add to both properties, source and destination. It would be sweet to create new instance of reference types in properties too. Just a suggestion :) – Andrija Nov 18 '10 at 12:20
  • @Andrija: Once you start getting into conditional cloning, I think it'll get really messy, really quickly... – Jon Skeet Nov 18 '10 at 14:03
  • Following your comment, how would you redesign / rename the API, Jon? – cregox Apr 09 '12 at 18:52
  • @Cawas: Following which comment? – Jon Skeet Apr 09 '12 at 19:17
  • @JonSkeet under your answer, in parenthesis: "*(I'd also probably redesign the API a bit in terms of naming if I were starting from scratch, but I don't want to break existing users...)*" – cregox Apr 09 '12 at 19:35
  • 2
    @Cawas: Ah, sorry - I was looking at the comments in Stack Overflow terminology :) For one thing I'd give it a *noun* name, e.g. `PropertyCopier`. I'd have to think a bit more about it and see some use cases to redesign it properly, to be honest. – Jon Skeet Apr 09 '12 at 20:18
  • Cool. I was just wondering while [researching about all this](http://stackoverflow.com/questions/10079433/in-c-sharp-what-are-our-options-to-clone-an-object-or-copy-its-properties). Naming can become very relevant here, and I thought maybe you already had this with new terminology... Thanks for the feedback and sorry for the shameless plug! ;) – cregox Apr 09 '12 at 20:31
  • @JonSkeet What if you are trying to copy from an Entity Type to a POCO, where the Entity has a Property type int, and you are translating to an Enum... the following line fails... if (!targetProperty.PropertyType.IsAssignableFrom(sourceProperty.PropertyType))... Is there a way to include an enumeration cast? – DRobertE Jul 08 '14 at 18:23
  • @denas: You'd probably want to add explicit handling for that, checking whether it's an enum. – Jon Skeet Jul 08 '14 at 18:31
  • @JonSkeet Tried targetProperty.PropertyType.IsAssignableFrom(typeof(Enum)) but that still fails – DRobertE Jul 08 '14 at 18:33
  • @denas: Yes, it would, because you can't assign `Enum` to any particular enum... Try using `targetProperty.PropertyType.IsEnum`. – Jon Skeet Jul 08 '14 at 18:34
  • @JonSkeet Ok, that tells me if the target(POCO) is an enum. Now, can a binding be added so it knows how to cast from the Entity (int) to whatever enum type is in the target(POCO)? I'm just very unfamiliar with Expression Bindings – DRobertE Jul 08 '14 at 18:38
  • @denas: You'd need to check whether the source was `int`, basically. – Jon Skeet Jul 08 '14 at 18:41
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/56979/discussion-between-denas-and-jon-skeet). – DRobertE Jul 08 '14 at 19:08
  • @JonSkeet this throwing error for getter only properties, Can you guide how can we take care ? – Kaushik Thanki May 02 '19 at 12:00
  • 1
    @KaushikThanki: Well it can't call the setter for a property if that setter doesn't exist... how would you *expect* that to work? Or do you just want it to skip those properties? (If so, just change the bit that throws an exception for write-only properties to use `continue;` to keep going instead...) – Jon Skeet May 02 '19 at 12:05
  • @JonSkeet thx,, after digging the code i got the solution , however thx for giving solution .. – Kaushik Thanki May 02 '19 at 13:08
57

Here's a short and sweet version, since you said both of your objects are of the same type:

foreach (PropertyInfo property in typeof(YourType).GetProperties().Where(p => p.CanWrite))
{
    property.SetValue(targetObject, property.GetValue(sourceObject, null), null);
}
Shimmy Weitzhandler
  • 101,809
  • 122
  • 424
  • 632
Daniel
  • 8,655
  • 5
  • 60
  • 87
  • 3
    I've been avoiding reflection-based solutions because they were all too complicated. This is wonderfully simple. One clarification: this is a *shallow* copy. – ToolmakerSteve Mar 12 '21 at 02:44
  • 2
    This is exactly what I was stumbling around for, was just missing the second half of the SetValue. Thank you! – jon.r Feb 22 '22 at 14:38
28

Building off of Steve's method, I went with the extension method approach. This uses my base class as type but should be useable even using object as the param types. Works great for my uses.

using System.Reflection;
//*Namespace Here*
public static class Ext
{
    public static void CopyProperties(this EntityBase source, EntityBase destination)
    {
        // Iterate the Properties of the destination instance and  
        // populate them from their source counterparts  
        PropertyInfo[] destinationProperties = destination.GetType().GetProperties(); 
        foreach (PropertyInfo destinationPi in destinationProperties)
        {
            PropertyInfo sourcePi = source.GetType().GetProperty(destinationPi.Name);     
            destinationPi.SetValue(destination, sourcePi.GetValue(source, null), null);
        } 
    }
}

Usage looks like this:

item1.CopyProperties(item2);

Now Item2 has the same property data as item1.

Daniel
  • 291
  • 3
  • 3
13

This short and simple Extension method will allow you to copy matching properties from one object to another with the check of Null value and is writable.

public static void CopyPropertiesTo(this object fromObject, object toObject)
    {
        PropertyInfo[] toObjectProperties = toObject.GetType().GetProperties();
        foreach (PropertyInfo propTo in toObjectProperties)
        {
            PropertyInfo propFrom = fromObject.GetType().GetProperty(propTo.Name);
            if (propFrom!=null && propFrom.CanWrite)
                propTo.SetValue(toObject, propFrom.GetValue(fromObject, null), null);
        }
    }
Ashdeep Singh
  • 130
  • 1
  • 4
9

Modification of Daniel version to avoid exceptions.

foreach (PropertyInfo property in typeof(YourType).GetProperties())
{
  if (property.CanWrite)
  {
    property.SetValue(marketData, property.GetValue(market, null), null);
  }
}
arteny
  • 339
  • 1
  • 4
  • 14
8

Basically in 2019 we should probably use more up-to-date language features, like expression trees and compiled lambda-expressions, instead of Reflection

As I was unable to find a "shallow cloner" that meets my requirements (speed most of all), I decided to create one myself. It enumerates all gettable/settable properties and then creates a Block expression that's then compiled and cached. Which makes it almost 13 times faster than the popular AutoMapper. Usage is very simple:

DestType destObject = PropMapper<SourceType, DestType>.From(srcObj);

You can view the full source here: https://github.com/jitbit/PropMapper

meum
  • 112
  • 7
Alex from Jitbit
  • 53,710
  • 19
  • 160
  • 149
  • 1
    MIT License is kind of a bummer there.. for a small functionality the whole license must be bundled and mainained. – Max Oct 24 '19 at 12:55
  • @Max I'm not really good at this, which license should I choose? I always thought MIT is the most simple and permissive (as in "do whatever you want") – Alex from Jitbit Jun 05 '20 at 08:54
  • 3
    It is the most simple and permissive. All you have to do is include the license in the source code, this isn't difficult. – nelsontruran Jun 24 '20 at 21:58
  • What is the namespace? Installed it via Nuget, VS can't pick up using statement, and readme does not say that either. – Pawel Sep 29 '20 at 07:44
  • @Pawel It's "Jitbit.Utils" but you can check the source ;) – Alex from Jitbit Sep 29 '20 at 07:56
  • @Alex Thanks, I used Jitbit.Utils but vs didn't piked it up. Let's call it a 'vs thing' ;) – Pawel Sep 29 '20 at 18:12
  • @AlexfromJitbit Really interesting. What do you think about using a TypeDescriptor ? – Pao'lino Apr 12 '23 at 07:46
3

For several years I'm using a popular library for that named ValueInjecter

nuget: https://www.nuget.org/packages/ValueInjecter/

github: https://github.com/omuleanu/ValueInjecter

target.InjectFrom(source);
target.InjectFrom<Injection>(source);
target.InjectFrom(new Injection(parameters), source);
target.InjectFrom<Injection>(); // without source

Note that even that the basic solutions are pretty simple (see other answers), there are plenty of edge cases (e.g. deep copy, generics, null values) and optimizations (e.g cache the reflected properties) so better to use maintained library for that.

Aviko
  • 1,139
  • 12
  • 21
3

There's ICloneable and object.MemberwiseClone (shallow copy) (these create a whole new object, so might not meet your requirements).

You could use reflection to do it yourself (inherit from a base class so you don't have to re-implement).

Or you could code generate it.

Cade Roux
  • 88,164
  • 40
  • 182
  • 265
3

You can use serialization to deep clone the object:

public static T DeepClone<T>(this T objectToClone) where T: BaseClass
{
    BinaryFormatter bFormatter = new BinaryFormatter();
    MemoryStream stream = new MemoryStream();
    bFormatter.Serialize(stream, objectToClone);
    stream.Seek(0, SeekOrigin.Begin);
    T clonedObject = (T)bFormatter.Deserialize(stream);
    return clonedObject;
}

Classes would just have to be marked Serializable of course.

KyleMit
  • 30,350
  • 66
  • 462
  • 664
Andrija
  • 14,037
  • 18
  • 60
  • 87
  • Also, if you want to add a dependency on JSON.NET in favor of a dependency on `Serializable`, you can [serialize and deserialize into JSON](https://www.newtonsoft.com/json/help/html/SerializingJSON.htm) – KyleMit Dec 27 '17 at 18:32
  • 1
    This will create a new instance, which might not be what you intend to do, if you only want to change your properties value. – Matthieu Nov 06 '18 at 16:21
2

You might try something like this....

MyType destination = new MyType();
MyType source = new MyType();

// Iterate the Properties of the destination instance and 
// populate them from their source counterparts

PropertyInfo[] destinationProperties = destination.GetType().GetProperties();
foreach (PropertyInfo destinationPI in destinationProperties)
{
    PropertyInfo sourcePI = source.GetType().GetProperty(destinationPI.Name);

    destinationPI.SetValue(destination,
                           sourcePI.GetValue(source, null), 
                           null);
}
Steve
  • 21
  • 1
  • This deserves more upvotes since most of the later answers here are just minor variations of this answer, and this one works fine for me. – Steve Smith Mar 16 '22 at 11:48
2

Expanding on @Azerothians answer, i needed some additional requirements:

  1. needed a way to ignore null properties on the source object
  2. needed a way to ignore explicit properties
  3. wanted a way to coerce the datatype where possible to match e.g. int? to decimal? or long to int (due to unfortunate early schema decisions from a predecessor)
  4. wanted to know if properties had been copied or not (to determine if db update would be required)

    /// <summary>
    /// Extension for 'Object' that copies the properties to a destination object.
    /// </summary>
    /// <param name="source">The source.</param>
    /// <param name="destination">The destination.</param>
    /// <param name="PropertiesToIgnore">an optional list of property names which will NOT be copied</param>
    /// <param name="IgnoreNullProperties">when true will not update properties where the source is null</param>
    /// <param name="CoerceDataType">when true, will attempt to coerce the source property to the destination property (e.g. int to decimal) </param>
    /// <param name="ThrowOnTypeMismatch">when true, will throw a InvalidCastException if the data cannot be coerced</param>
    /// <exception cref="InvalidCastException">if there is a data type mismatch between source/destination and ThrowOnTypeMismatch is enabled and unable to coerce the data type.</exception>
    /// <returns>true if any properties were changed</returns>
    public static bool CopyProperties(this object source, object destination, IEnumerable<string> PropertiesToIgnore = null, bool IgnoreNullProperties = false, bool ThrowOnTypeMismatch = true, bool CoerceDataType = true)
    {
        if (source is null)
            throw new ArgumentNullException(nameof(source));
    
        if (destination is null)
            throw new ArgumentNullException(nameof(destination));
    
        // Getting the Types of the objects
        Type typeDest = destination.GetType();
        Type typeSrc = source.GetType();
    
        // Collect all the valid properties to map
        var results = (from srcProp in typeSrc.GetProperties()
                       let targetProperty = typeDest.GetProperty(srcProp.Name)
                       where srcProp.CanRead
                       && targetProperty != null
                       && (targetProperty.GetSetMethod(true) != null && !targetProperty.GetSetMethod(true).IsPrivate)
                       && (targetProperty.GetSetMethod().Attributes & MethodAttributes.Static) == 0
                       && !(
                           from i in PropertiesToIgnore ?? Enumerable.Empty<string>()
                           select i
                         ).Contains(srcProp.Name)
                       && (!IgnoreNullProperties || srcProp.GetValue(source, null) != null)
                       select new { sourceProperty = srcProp, targetProperty = targetProperty }).ToList();
    
        bool PropertyChanged = false;
        //map the properties
        foreach (var props in results)
        {
            var srcValue = props.sourceProperty.GetValue(source, null);
            var dstValue = props.targetProperty.GetValue(destination, null);
            if (props.targetProperty.PropertyType.IsAssignableFrom(props.sourceProperty.PropertyType))
                props.targetProperty.SetValue(destination, srcValue, null);
            else
            {
                try
                {
                    if (!CoerceDataType)
                        throw new InvalidCastException($"Types do not match, source: {props.sourceProperty.PropertyType.FullName}, target: {props.targetProperty.PropertyType.FullName}.");
    
                    if (srcValue != null)
                    {
                        // determine if nullable type
                        Type tgtType = Nullable.GetUnderlyingType(props.targetProperty.PropertyType);
                        // if it is, use the underlying type
                        // without this we cannot convert int? -> decimal? when value is not null
                        if (tgtType != null)
                            props.targetProperty.SetValue(destination, Convert.ChangeType(srcValue, tgtType, CultureInfo.InvariantCulture), null);
                        else // otherwise use the original type
                            props.targetProperty.SetValue(destination, Convert.ChangeType(srcValue, props.targetProperty.PropertyType, CultureInfo.InvariantCulture), null);
                    }
                    else // if null we can just set it as null
                        props.targetProperty.SetValue(destination, null, null);
                }
                catch (Exception ex)
                {
                    if (ThrowOnTypeMismatch)
                        throw new InvalidCastException($"Unable to copy property {props.sourceProperty.Name} with value {srcValue} from object of type ({typeSrc.FullName}) to type ({typeDest.FullName}), Error: {ex.Message}");
                    // else ignore update
                }
                var newdstValue = props.targetProperty.GetValue(destination, null);
                if (newdstValue == null && dstValue != null || !newdstValue.Equals(dstValue))
                    PropertyChanged = true;
            }
        }
    
        return PropertyChanged;
    }
    
Justin
  • 1,303
  • 15
  • 30
1

Maybe this post is a little bit old, answers are good but when you need to map a lot of objects into a target Type - looping through properties could be costly (Imaging 100 props and more).

I use this AutoMapFactory method (only require LinQ), it will iterates only once in the properties and the mapping of each object will be fast (100000 props/seconds)

private Func<S,T> AutoMapFactory<S,T>() where T: class, new() where S : class
        {
            List<Action<T, S>> mapActions = typeof(T).GetProperties().Where(tp => tp.CanWrite)
                .SelectMany(tp => typeof(S).GetProperties().Where(sp => sp.CanRead)
                .Where(sp => sp.Name == tp.Name && tp.PropertyType.IsAssignableFrom(sp.PropertyType))
                .Select(sp => (Action<T,S>)((targetObj, sourceObj) => 
                    tp.SetValue(targetObj, sp.GetValue(sourceObj)))))
                .ToList();

            return sourceObj => {
                if (sourceObj == null) return null;

                T targetObj = new T();
                mapActions.ForEach(action => action(targetObj, sourceObj));
                return targetObj;
            };
        }

How to use this:

...
var autoMapper = AutoMapFactory<SourceType, TargetType>(); //Get Only 1 instance of the mapping function
...
someCollection.Select(item => autoMapper(item)); //Almost instantaneous
...
0

I have taken all what has been written above by @Shimmy Weitzhandler and sligtly modified. Since I use this method when I have to define several object with the same properties I made a function accepting a variable number of elements:

public static void CopyProperties<T>(T source, params T[] dests)
{
    if(source == null)
        return;

    foreach (var dest in dests)
    {
        foreach (System.Reflection.PropertyInfo property in typeof(Button).GetProperties().Where(p => p.CanWrite))
            property.SetValue(dest, property.GetValue(source, null), null);
    }
}

With that you can define one or several elements. E.g.:

Helper.CopyProperties(btn_Src, bt_Dest1);

or

Helper.CopyProperties(btn_Src, bt_Dest1, btn_Dest2, btn_Dest3);

I made it static for I have it in my Helper library

Patrick
  • 3,073
  • 2
  • 22
  • 60
0

If you want something like ApplyProperties, you could write an extension method on Object which would do what you need. Just realize that such an extension method wouldn't be "pure", or side-effect free. But if you need the capability, its a way to accomplish it.

jrista
  • 32,447
  • 15
  • 90
  • 130
-3
public TestClass {
    public TestName {get;set;}
}
public void submain()
{
    var originalTestClass = new TestClass()
    {
        TestName  ="Test Name";
    };

    var newTestClass = new TestClass();
     newTestClass.CopyPropertiesFrom(originalTestClass);
}
  • 3
    Please describe, what was the problem, and how will this snippet solve it, to help future readers understand this answer. And, the queston is more than 10 years old... – FZs Jun 28 '19 at 03:47