将值从一个对象复制到另一个对象(不同类型)

时间:2012-12-26 21:33:59

标签: c#

我需要将一个对象的一些属性复制到另一个对象。但是,某些属性需要从decimal到int的类型转换。

我发现这个问题非常有用: Copy values from one object to another

但是,我无法弄清楚如何修改Jon Skeet和Marc Gravell的MiscUtil中的代码以检查属性类型,如果源是十进制且目标是int,则调用Convert.ToIn32()。

以下是MiscUtil的代码,我想弄清楚如何修改:

using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Reflection;

namespace MiscUtil.Reflection
{
    /// <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>.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.
        /// </summary>
        private static class PropertyCopier<TSource> where TSource : class
        {
            private static readonly Func<TSource, TTarget> copier;
            private static readonly Exception initializationException;

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

            static PropertyCopier()
            {
                try
                {
                    copier = BuildCopier();
                    initializationException = null;
                }
                catch (Exception e)
                {
                    copier = null;
                    initializationException = e;
                }
            }

            private static Func<TSource, TTarget> BuildCopier()
            {
                ParameterExpression sourceParameter = Expression.Parameter(typeof(TSource), "source");
                var bindings = new List<MemberBinding>();
                foreach (PropertyInfo sourceProperty in typeof(TSource).GetProperties())
                {
                    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.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)));
                }
                Expression initializer = Expression.MemberInit(Expression.New(typeof(TTarget)), bindings);
                return Expression.Lambda<Func<TSource,TTarget>>(initializer, sourceParameter).Compile();
            }
        }
    }
}

3 个答案:

答案 0 :(得分:4)

如果你有

public class Foo
{
    public decimal Value { get; set; }
}

public class Bar
{
    public int Value { get; set; }
}

然后使用AutoMapper(可从NuGet获得),您可以将对象Foo映射到对象Bar,如下所示:

Mapper.CreateMap<Foo, Bar>();
Foo foo = new Foo() { Value = 10.5M };
var bar = Mapper.Map<Bar>(foo);
// bar.Value = 10;

答案 1 :(得分:1)

我们可以使用System.Reflection。 遵循这个功能:

 public static T CloneData<T>(object source)
    {
        var target = (T)Activator.CreateInstance(typeof(T));

        Type objTypeBase = source.GetType();
        Type objTypeTarget = target.GetType();

        PropertyInfo _propinfo = null;
        var propInfos = objTypeBase.GetProperties(BindingFlags.Instance | BindingFlags.Public);
        foreach (var propInfo in propInfos)
        {
            try
            {
                _propinfo = objTypeTarget.GetProperty(propInfo.Name, BindingFlags.Instance | BindingFlags.Public);
                if (_propinfo != null)
                {
                    _propinfo.SetValue(target, propInfo.GetValue(source));
                }
            }
            catch (ArgumentException aex) { if (!string.IsNullOrEmpty(aex.Message)) continue; }
            catch (Exception ex) { if (!string.IsNullOrEmpty(ex.Message)) return default(T);  }
        }

        return target; 
    }     

假设我们有两个类:

public class A
{
    public string Prop1 {get ; set; }
    public string Prop2 {get ; set; }
    public string Prop3 {get ; set; }
    public string Prop4 {get ; set; }
}

public class B
{
    public string Prop2 {get ; set; }
    public string Prop3 {get ; set; }
}

我们写道:

var a = new A
        {
            Prop1 = "A",
            Prop2 = "B",
            Prop3 = "C",
            Prop4 = "D",
        };

var b = CloneData<B>(a);

我们将获得一个B类实例,其中Prop1和Prop3值是从A。

复制的

答案 2 :(得分:0)

您可以查看类似

的类型
        int x = 4;
        if(x.GetType()== typeof(int))
        {
            ///DO Stuff
        }

        if(x.GetType()==typeof(decimal)
           {
                ///Do stuff
             }