将属性值从一个对象自动应用到同一类型的另一个对象?

时间:2021-09-06 07:22:34

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.

给定2个类型为T的对象A和B,我想将A中的属性值分配给B中的相同属性,而不对每个属性进行显式赋值。

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?

可能吗?

11 个解决方案

#1


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.

我在MiscUtil中有一个名为PropertyCopy的类型,它做了类似的事情 - 虽然它创建了一个目标类型的新实例并将属性复制到其中。

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:

在本答案底部的代码块中,我扩展了该类的功能。要从一个实例复制到另一个实例,它在执行时使用简单的PropertyInfo值 - 这比使用表达式树慢,但另一种方法是编写一个动态方法,我不太热。如果表现对你来说绝对至关重要,请告诉我,我会看到我能做些什么。要使用该方法,请编写如下内容:

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).

(其中Copy是使用类型推断调用的泛型方法)。

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.

我还没准备好完成一个完整的MiscUtil版本,但这里是更新的代码,包括注释。我不会为SO编辑器重新编写它们 - 只需复制整个块。

(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...)

(如果我从头开始,我也可能在命名方面重新设计API,但我不想打破现有用户...)

#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

#2


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.

因为我相信Jon的版本太复杂而且Steve的版本太简单了,我喜欢Daniel对扩展类的想法。

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

我想做自己的精益和平均版本的志愿者。以上所有内容。 :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

因为我很无聊,并且评论建议使用linq版本

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);
        }
    }
}

#3


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.

建立史蒂夫的方法,我采用了扩展方法。这使用我的基类作为类型,但即使使用object作为param类型也应该可用。适合我的用途。

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.

现在Item2与item1具有相同的属性数据。

#4


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())
{
    property.SetValue(targetObject, property.GetValue(sourceObject, null), null);
}

#5


Modification of Daniel version to avoid exceptions.

修改Daniel版本以避免异常。

foreach (PropertyInfo property in typeof(YourType).GetProperties())
{
  if (property.CanWrite)
  {
    property.SetValue(marketData, property.GetValue(market, null), null);
  }
}

#6


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.

当然,类必须标记为Serializable。

#7


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

有ICloneable和object.MemberwiseClone(浅拷贝)(这些创建了一个全新的对象,因此可能无法满足您的要求)。

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.

或者您可以编码生成它。

#8


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);
}

#9


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.

这个简短而简单的Extension方法允许您将匹配的属性从一个对象复制到另一个对象,并检查Null值并且是可写的。

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);
        }
    }

#10


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

几年来,我正在使用一个名为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.

请注意,即使基本解决方案非常简单(参见其他答案),也有很多边缘情况(例如深拷贝,泛型,空值)和优化(例如缓存反射属性),因此最好使用维护库。

#11


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.

如果你想要像ApplyProperties这样的东西,你可以在Object上编写一个扩展方法,它可以满足你的需要。只是意识到这样的扩展方法不会是“纯粹的”,或者是无副作用的。但是如果你需要这种能力,它就是一种完成它的方法。

#1


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.

我在MiscUtil中有一个名为PropertyCopy的类型,它做了类似的事情 - 虽然它创建了一个目标类型的新实例并将属性复制到其中。

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:

在本答案底部的代码块中,我扩展了该类的功能。要从一个实例复制到另一个实例,它在执行时使用简单的PropertyInfo值 - 这比使用表达式树慢,但另一种方法是编写一个动态方法,我不太热。如果表现对你来说绝对至关重要,请告诉我,我会看到我能做些什么。要使用该方法,请编写如下内容:

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).

(其中Copy是使用类型推断调用的泛型方法)。

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.

我还没准备好完成一个完整的MiscUtil版本,但这里是更新的代码,包括注释。我不会为SO编辑器重新编写它们 - 只需复制整个块。

(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...)

(如果我从头开始,我也可能在命名方面重新设计API,但我不想打破现有用户...)

#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

#2


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.

因为我相信Jon的版本太复杂而且Steve的版本太简单了,我喜欢Daniel对扩展类的想法。

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

我想做自己的精益和平均版本的志愿者。以上所有内容。 :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

因为我很无聊,并且评论建议使用linq版本

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);
        }
    }
}

#3


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.

建立史蒂夫的方法,我采用了扩展方法。这使用我的基类作为类型,但即使使用object作为param类型也应该可用。适合我的用途。

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.

现在Item2与item1具有相同的属性数据。

#4


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())
{
    property.SetValue(targetObject, property.GetValue(sourceObject, null), null);
}

#5


Modification of Daniel version to avoid exceptions.

修改Daniel版本以避免异常。

foreach (PropertyInfo property in typeof(YourType).GetProperties())
{
  if (property.CanWrite)
  {
    property.SetValue(marketData, property.GetValue(market, null), null);
  }
}

#6


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.

当然,类必须标记为Serializable。

#7


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

有ICloneable和object.MemberwiseClone(浅拷贝)(这些创建了一个全新的对象,因此可能无法满足您的要求)。

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.

或者您可以编码生成它。

#8


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);
}

#9


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.

这个简短而简单的Extension方法允许您将匹配的属性从一个对象复制到另一个对象,并检查Null值并且是可写的。

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);
        }
    }

#10


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

几年来,我正在使用一个名为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.

请注意,即使基本解决方案非常简单(参见其他答案),也有很多边缘情况(例如深拷贝,泛型,空值)和优化(例如缓存反射属性),因此最好使用维护库。

#11


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.

如果你想要像ApplyProperties这样的东西,你可以在Object上编写一个扩展方法,它可以满足你的需要。只是意识到这样的扩展方法不会是“纯粹的”,或者是无副作用的。但是如果你需要这种能力,它就是一种完成它的方法。