2014-07-08 4 views
1

Jon Skeets 속성 복사를 사용하여 복사기를 만들려고합니다. 그것은 모든 속성,하지만 enums 잘 작동합니다. 열거 형을 거의 성공하지 못하게하려면 메서드를 변경하는 시도를 여러 번 시도했습니다. 다른 사람이이 작업을 수행하는 방법에 대한 아이디어가 있는지 궁금합니다.엔티티 int가 POCO의 Entum 인 Entity 객체를 POCO에 복사합니다.

존 Skeets 원래 내 변경이에 BUILDCOPIER 방법에 의견

호출을 구분 함께있는

 var result = Common.PropertyCopy<POCO>.CopyFrom(Entity); 

원래 존 소총 코드

/// <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. 
/// http://www.yoda.arachsys.com/csharp/miscutil/ 
/// </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); 
       } 

       // THIS IS FALSE FOR SOURCE(INT) TARGET ENUMS 
       if (!targetProperty.PropertyType.IsAssignableFrom(sourceProperty.PropertyType)) 
       { 
        //ADDED FOLLOWING TO HANDLE COPY FROM INT TO ENUM 
        ///////////////////////////////////////////////////////////////////////////////////////////////////// 
        // Special Case because Entities are created with property as ints, not enum types 
        if (targetProperty.PropertyType.IsEnum && (sourceProperty.PropertyType == typeof(int))) 
        { 
         var expressionparam = Expression.Parameter(sourceProperty.PropertyType); 
         // cast the entity source as the enum target 
         var cast = Expression.Convert(expressionparam, targetProperty.PropertyType); 
         // add to the binding tree 
         bindings.Add(Expression.Bind(targetProperty, Expression.Property(cast, sourceProperty))); 
         continue; 
        } 
        ///////////////////////////////////////////////////////////////////////////////////////////////////// 

        throw new ArgumentException("Property " + sourceProperty.Name + " has an incompatible type in " + typeof(TTarget).FullName); 
       } 
      Expression initializer = Expression.MemberInit(Expression.New(typeof(TTarget)), bindings); 
      return Expression.Lambda<Func<TSource, TTarget>>(initializer, sourceParameter).Compile(); 
     } 
    } 
} 

열거

public enum NotificationType 
{ 
    InAppNotificiation = 0, 
    EmailNotification, 
    SMS 
} 
유형 'Models.Enums에 대해 정의되지 않은3210

엔티티 클래스 EF하여 라인

bindings.Add(Expression.Bind(targetProperty, Expression.Property(cast, sourceProperty))); 

재산권'INT32 NotificationType '던져

public class Entity 
{ 
    public int ProcessedStatus { get; set; } 
    public int Priority { get; set; } 
    public System.Guid NotifyToUserId { get; set; } 
    public string NotifyFrom { get; set; } 
    public string NotifySubject { get; set; } 
    public string NotifyMessageBody { get; set; } 
    public int NotificationType { get; set; } <-- Stored as int in DB 

    public virtual MercuryUser MercuryUser { get; set; } <--complex type 
} 

POCO 클래스

public class POCO 
{ 
    public int ProcessedStatus { get; set; } 
    public int Priority { get; set; } 
    public System.Guid NotifyToUserId { get; set; } 
    public string NotifyFrom { get; set; } 
    public string NotifySubject { get; set; } 
    public string NotifyMessageBody { get; set; } 
    public NotificationType NotificationType { get; set; } <-- ENUM TYPE 

    public MyUser MyUser { get; set; } <-- complex type 
} 

예외를 생성합니다. 알림 유형

+0

EF는 코드 우선 POCO와 enum (버전 5 이후)을 지원하므로 더 이상 하나의 객체를 다른 객체로 복사 할 필요가 없습니다. –

+0

프로젝트 결정에 앞서 디자인 결정이 내려졌고 코드가 처음 사용되지 않았습니다. – DRobertE

+0

대상 클래스를 작성할 때 코드를 효과적으로 복제하지 않습니까? 어쨌든 AutoMapper와 같은 매핑 라이브러리를 사용하여 리플렉션 코드를 직접 작성하지 않고 하나의 DTO를 다른 맵핑에 매핑 할 수 있습니다. 매핑 라이브러리는 또한 캐싱 매핑을 처리하므로 새 객체를 매핑 할 때마다 속성 검색을 반복하지 않아도됩니다. –

답변

0

그래서이 게시물을 발견했습니다 C# Using Reflection to copy base class properties 이것을 시도해 보았습니다. 때로는 단순한 것만으로도 작동합니다 ... 왜이 것이 열거 형을 설정하는지 그리고 복잡한 유형에서 폭발하지 않는지 확실하지 않습니다. 아마도 람다 표현식이 객체를 해석하는 방법 일 것입니다. 그것은 열거 형, 특히 열거 형에서 할당 할 수 있는지 검사하지 않고 int 및 속성 이름을 기반으로 설정합니다. isAssignable가 int 유형의 sourceproperty와 기본 유형이 같은 경우 enum 유형의 targetproperty에서 설정하려고하면 직관적 인 카운터 유형이 아닙니다. 누구나 이것에 대한 통찰력을 얻을 수 있다면 좋겠지 만, 지금은 아래에 나와있는 더 간단한 복사 방법을 사용하려고합니다. 아래쪽은 복사기를 저장하지 않으므로 매번 복사기를 거쳐야합니다.

public static T1 CopyFrom<T1, T2>(T1 obj, T2 otherObject) where T1 : class where T2 : class 
    { 
     PropertyInfo[] srcFields = otherObject.GetType().GetProperties(
      BindingFlags.Instance | BindingFlags.Public | BindingFlags.GetProperty); 

     PropertyInfo[] destFields = obj.GetType().GetProperties(
      BindingFlags.Instance | BindingFlags.Public | BindingFlags.SetProperty); 

     foreach (var property in srcFields) 
     { 
      var dest = destFields.FirstOrDefault(x => x.Name == property.Name); 
      if (dest != null && dest.CanWrite) 
       dest.SetValue(obj, property.GetValue(otherObject, null), null); 
     } 

     return obj; 
    }