2017-05-20 11 views
1

기존 데이터베이스에 대해 루틴을 작성해야합니다. 이 데이터베이스에는 구조가 동일하지만 이름이 다른 여러 테이블이 있습니다 (설계하지 않았으므로 데이터베이스 설계 변경을 제안하지 마십시오). 필자는 EF에서이 글을 쓰고 있는데, 모델은 데이터베이스에서 먼저 작성되었습니다.C# 리플렉션을 사용하여 한 유형의 오브젝트 값을 다른 오브젝트로 복사

이 상황에서 가장 좋은 옵션은 동일한 속성을 가진 클래스를 만들고 EF 모델에서 일반 모델로 데이터를 복사하는 제네릭 형식을 허용 할 수있는 루틴을 만드는 것입니다. 루틴 구현하지

 private static void CopyFlavorToGenericList<T1, T2>(List<T1> fromList, List<T2> toList){ 
     foreach (var t in fromList) 
     { 
      //(As you can see, I have tried entering the foreach loop a both ways 
      //foreach (var p in typeof(T1).GetProperties()) 

      foreach (var p in typeof(T2).GetProperties()) 
      { 
       if (p != null && p.CanWrite) 
       { 
        dynamic newObject = null; 
        p.SetValue((T2)newObject, p.GetValue(t, null), null); 
       } 
      } 

      toList.Add(toObject); 
     } 
    } 

:

내 모델 :

// Sample EF database-first created model 
    namespace SampleDataModel.Models 
    { 
     using System; 
     using System.Collections.Generic; 

     public partial class SampleClassFlavorOne 
     { 
      public int Id {get; set;} 
      public string PropertyOne {get; set;} 
      public string Property2 {get; set;} 
      public DateTime Property3 {get; set;} 
     } 
    } 

    // Sample of generic class I created 
    public class GenericSampleClass{ 
     public int Id {get; set;} 
     public string PropertyOne {get; set;} 
     public string Property2 {get; set;} 
     public DateTime Property3 {get; set;} 
    } 

내 일상 아무리 노력할

switch (flavor){ 
     case "FlavorOne": 
      List<SampleClassFlavorOne> _baseFlavor = db.SampleClassFlavorOne.ToList(); 
      List<GenericSampleClass> _genericFlavor = new List<GenericSampleClass>(); 

      CopyFlavorToGenericList<SampleClassFlavorOne, GenericSampleClass>(_baseFlavor, _genericFlavor); 
      break; 
    } 

을, 난 항상 얻을 :

,536,

mscorlib.dll에서 'System.Reflection.TargetException'유형의 예외가 발생했지만 사용자 코드에서 처리되지 않았습니다. 추가 정보 : 오브젝트가 목표 유형과 일치하지 않습니다.

제가 누락 된 항목을 파악할 수 없습니다.

  1. 무엇이 누락 될 수 있습니까?
  2. 잘못된 길로 가고 있습니까? 그렇다면 이러한 조건에서 내가하고 싶은 일을하는 올바른 방법은 무엇입니까?

감사합니다.

답변

1

GetProperties()을 호출하면 해당 유형에 이 적용되는 PropertyInfo 개체가 생성됩니다. 따라서 GetValue()을 호출 할 때 잘못된 유형의 객체에서 값을 가져 오려고합니다.

e.e. PropertyInfo 개체를 가져 오는 데 사용되는 형식 인 T2GenericSampleClass이지만 GetValue() 메서드에 전달하는 개체 유형은 SampleClassFlavorOne입니다. 대안으로, 에서 속성을 가져 오는 경우에도 동일한 문제가 발생하지만 SetValue() 메서드를 사용하면 PropertyInfo 객체가 출처 인 경우 GenericSampleClass 유형의 객체를 전달 (이론적으로 & hellip;하지만 실제로는 "참고 :"참조)하면됩니다. SampleClassFlavorOne 유형.

올바르게하려면 정확하게 개체를 클래스에서 모두 클래스로 가져와 적절한 유형의 개체와 함께 사용해야합니다. 예를 들면 다음과 같습니다.

private static void CopyFlavorToGenericList<T1, T2>(List<T1> fromList, List<T2> toList) where T2 : new() 
{ 
    var map = from p1 in typeof(T1).GetProperties() 
       join p2 in typeof(T2).GetProperties() 
        on p1.Name equals p2.Name 
       select new { From = p1, To = p2 }; 

    foreach (var t in fromList) 
    { 
     T2 toObject = new T2(); 

     foreach (var copyItem in map) 
     { 
      if (copyItem.To.CanWrite) 
      { 
       copyItem.To.SetValue(toObject, copyItem.From.GetValue(t)); 
      } 
     } 

     toList.Add(toObject); 
    } 
} 

참고 : 새 개체를 만드는 방법에 문제가있었습니다. 나는 심지어 당신이 무엇을 의미하는지 모르겠다. dynamic을 사용했는데 효과가 없었을 것이다. 유용하지 않은 대상 객체의 값으로 null을 전달하는 중이었습니다.

필요에 따라 대상 개체의 인스턴스를 만들 수 있어야하며 일반 메서드에서이를 수행하는 방법은 일반 형식 매개 변수에 new() 제약 조건을 추가하여 대상 형식에 매개 변수없는 구성, 사실 new T2()이라는 표현식을 사용하여 객체의 새 인스턴스를 만들 수 있습니다.

+0

피터 감사합니다! 특히, 코드를 제공 할뿐만 아니라 훌륭한 설명을 해주셔서 감사합니다! 나는 결심뿐만 아니라 내가 가지고있는 문제를 완전히 이해한다. 나는 네 자신을 약간 지키라. 그것은 내가이 사이트에서 본 솔루션 중 일부를 시험해보기위한 마지막 도랑 노력의 일부였습니다. 어떻게 작동하는지 궁금합니다. 나는'T2 toObject = new T2();'작업을하는 방법을 알아낼 수 없었다. 다시 한 번 감사드립니다! +1하고 답하십시오. – MattCash

+0

주제에 대한 한 가지 더 질문 : 나는 그 자체로 반영이 약간의 성과에 부딪쳤다는 것을 이해합니다. 변수'map'을 만들어야 만 성능이 향상 될 수 있습니까? 솔루션을 살펴보면, 필자는 (필자의 fromList의 모든 객체보다는) 한 번 반사를 사용하고 있기 때문에 실제로이 히트를 줄이고 있다고 말하고 싶다. 내가 맞을 까? – MattCash

+0

@Matt : 예,'map' 개체를 한 번 만드는 것이 목록의 모든 개체에 대해 수행하는 것보다 낫습니다. GetValue() 및 SetValue() 메서드를 호출하는 비용은 여전히 ​​있지만 속성에 직접 액세스하는 것보다 느립니다. 반사는 다른 기술에 비해 느리지 만이 코드를 실행해야하는 빈도에 따라 문제가 될 수도 있고 아닐 수도 있습니다. 속도가 문제가되면, 컴파일 할 수있는 속성에 액세스하기위한'Expression' 객체를 만들고 복사 메소드 호출을 통해 사전을 사용하여 문제를 해결할 수 있습니다. –