40

To copy the property values from one object to another, we usually achieve with following syntax:

ca.pro1 = cb.pro2;
ca.pro2 = cb.pro2;

where ca and cb are of the same class.

Is there any simpler synatx or utility method to help us to achieve the same effect?

Thank you.

Ricky
  • 34,377
  • 39
  • 91
  • 131
  • This is what you're looking for: [Cloning objects in C#](https://stackoverflow.com/questions/78536/cloning-objects-in-c) – Leniel Maccaferri Aug 10 '10 at 03:21
  • 2
    Cloning is not the same as copying in the context of this question: The OP doesn't say it is okay to instantiate an object. The answers provided here are useful and distinct from the answers found under "cloning" questions. – Design.Garden Sep 14 '21 at 03:02

5 Answers5

58
public static void CopyPropertiesTo<T, TU>(this T source, TU dest)
{
    var sourceProps = typeof (T).GetProperties().Where(x => x.CanRead).ToList();
    var destProps = typeof(TU).GetProperties()
            .Where(x => x.CanWrite)
            .ToList();

    foreach (var sourceProp in sourceProps)
    {
        if (destProps.Any(x => x.Name == sourceProp.Name))
        {
            var p = destProps.First(x => x.Name == sourceProp.Name);
            if(p.CanWrite) { // check if the property can be set or no.
                p.SetValue(dest, sourceProp.GetValue(source, null), null);
            }
        }

    }

}
sikanderBabwani
  • 1,289
  • 1
  • 9
  • 10
Yargicx
  • 1,704
  • 3
  • 16
  • 36
  • 9
    Why `if(p.CanWrite)`? destProps are already of CanWrite type. – Emanuele Apr 12 '18 at 14:02
  • 2
    You can optimize like this : `var p = destProps.FirstOrDefault(x => x.Name == sourceProp.Name);` `if (p != null)` `p.SetValue(dest, sourceProp.GetValue(source, null), null);` – A.Baudouin Dec 05 '19 at 08:09
15

If I am not mistaken with what is required, the way to easily achieve property value copy between two existing instances (even not of the same type) is to use Automapper.

  1. create mapping configuration
  2. and then call .Map(soure, target)

As long as you keep property in same type and in same naming convention, all should work.

Example:

MapperConfiguration _configuration = new MapperConfiguration(cnf =>
            {
                cnf.CreateMap<SourceType, TargetType>();
            });
var mapper = new Mapper(_configuration);
maper.DefaultContext.Mapper.Map(source, target)
st35ly
  • 1,215
  • 18
  • 24
12

This is a function that I used to copy members between models in ASP.NET MVC. While you seek a code that work for the same type, this code will also support other types that has the same properties.

It uses reflections, but in a more clean manner. Beware of the Convert.ChangeType: you might not need it; you could do a check on the type instead of converting.

public static TConvert ConvertTo<TConvert>(this object entity) where TConvert : new()
{
    var convertProperties = TypeDescriptor.GetProperties(typeof(TConvert)).Cast<PropertyDescriptor>();
    var entityProperties = TypeDescriptor.GetProperties(entity).Cast<PropertyDescriptor>();

    var convert = new TConvert();

    foreach (var entityProperty in entityProperties)
    {
        var property = entityProperty;
        var convertProperty = convertProperties.FirstOrDefault(prop => prop.Name == property.Name);
        if (convertProperty != null)
        {
            convertProperty.SetValue(convert, Convert.ChangeType(entityProperty.GetValue(entity), convertProperty.PropertyType));
        }
    }

    return convert;
}

Since this is an extension method, the usage is simple:

var result = original.ConvertTo<SomeOtherType>();
Pierre-Alain Vigeant
  • 22,635
  • 8
  • 65
  • 101
  • PropertyDescriptor.SetValue didn't work for me, had to use var convertProperties = typeof(TConvert).GetProperties(); - which gives you a List of PropertyInfo instead of PropertyDescriptor's – MHolzmayr Jun 09 '17 at 10:42
  • In Hindsight: "didn't work" meaning, the code ran, but it did not set any values, for example bool properties, b/c they had private setters (D'oh!). – MHolzmayr Jun 09 '17 at 10:44
  • This didnt work for me either, getting Invalid cast from 'System.Int32' to 'System.Nullable`1[[System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]] – Jean-Paul Dec 30 '18 at 00:07
  • @Jean-Paul It seem to fail when using nullable type. I invite you to find a solution and update this post. Or you should seek an existing library like Automapper. – Pierre-Alain Vigeant Dec 31 '18 at 20:28
3

not really. there is a MemberwiseClone() but that copies references directly meaning you would get a reference to the same object and that can be bad. You can implement the ICloneable interface and use that for a deep copy. I prefer making my own Clone() method though because the ICloneable interface returns an Object that needs to be cast.

Scott M.
  • 7,313
  • 30
  • 39
  • 3
    I wouldn't bother with ICloneable, it is impossible to properly implement it because the interface doesn't allow the caller to indicate what he means by "clone". – Jonathan Allen Aug 10 '10 at 03:23
  • i believe the de facto standard is a deep clone, but that also goes with what i said about making your own clone method, for better type safety, etc. – Scott M. Aug 10 '10 at 03:41
  • MemberwiseClone is not applicable to this question. It always creates a new object; this question is about updating fields in an **existing object**, from another object. – ToolmakerSteve Mar 12 '21 at 02:34
1
public static TTarget Convert<TSource, TTarget>(TSource sourceItem)
{
    if (null == sourceItem)
    {
        return default(TTarget);
    }

    var deserializeSettings = new JsonSerializerSettings { ObjectCreationHandling = ObjectCreationHandling.Replace,  };

    var serializedObject = JsonConvert.SerializeObject(sourceItem, deserializeSettings);

    return JsonConvert.DeserializeObject<TTarget>(serializedObject);
}

usage:

  promosion = YourClass.Convert<Promosion, PromosionExtension>(existsPromosion);
Gabriel
  • 377
  • 1
  • 3
  • 15
Xtremexploit
  • 319
  • 4
  • 7