2012-12-26 212 views
2

我需要將一個對象的某些屬性複製到另一個對象。但是,某些屬性需要從十進制到int的類型轉換。將值從一個對象複製到另一個對象(不同類型)

我發現這個問題是非常有用的: Copy values from one object to another

但是,我想不出如何修改喬恩斯基特和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(); 
      } 
     } 
    } 
} 
+2

你可以看看AutoMapper。這對於這類東西來說是非常有用的。 – w00

+0

我認爲AutoMapper,但我不想添加另一個DLL到我的項目。如果AutoMapper像Massive這樣的單人課程,我會這樣做。 – Steve

回答

4

如果你有

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

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

然後用AutoMapper(可從的NuGet)可以在地圖上對象Foo對象這樣吧:

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

你可以檢查類型如

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

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

我不確定在上面的BuildCopier方法中添加那種代碼的位置。有什麼建議麼? – Steve

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

我們會得到複製有PROP2和Prop3值B類的一個實例從A.

相關問題