2010-06-24 7 views
0

실버 눈금에 표시 할 (동적으로 생성 된 형식) 컬렉션을 만드는 중 하나는 가져 오기 (동적 생성 된 형식) 형식을 만든 다음 가져 오기 형식의 속성을 의 컬렉션 (동적으로 생성 된 타입) 두 가지 유형의 항목을 식별하는 Id 속성을 공유하는 그리드Object to Object 컬렉션의 속성 매핑

int Id {get; set}  
string Foo {get;set;} 
string FooFoo {get;set;} 

에 바인딩

즉 유형 (그리드 또는 가져 오기에이를 수)와 유형을 가져

int Id {get; set} 
string Foo {get;set} 

여기서 ids가 일치합니다. 나는 foos를 복사하려고합니다.

컬렉션의 한 유형에서 다른 유형으로 속성을 빠르게 매핑하는 방법은 무엇입니까?

편집

을 heres keymembers이 동일 할 때 기능은, 멤버 이름, 작품을 대표하는 사전 문자열 문자열을 통해 정의 된 매핑을 두 가지 유형의지도를하므로 스테판 덕분에 최종 Typemapper 구현 실버 라이트. 한 항목에서 다른 속성을 매핑합니다

public class TypeMapper 
{ 
    private readonly DynamicMethod _mapper; 


    public static DynamicMethod BuildMapper(Type fromType, 
              Type toType, 
              KeyValuePair<string, string> keyMemberMap, 
              Dictionary<string, string> memberMappings) 
    { 

     var method = new DynamicMethod("Map", typeof(bool), new[] { fromType, toType }); 

     // Preparing Reflection instances 
     MethodInfo getFromKeyMethod = fromType.GetMethod(
      string.Format("get_{0}", keyMemberMap.Key), 
      BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); 

     MethodInfo getToKeyMethod = toType.GetMethod(
      string.Format("get_{0}", keyMemberMap.Value), 
      BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); 

     ILGenerator gen = method.GetILGenerator(); 

     // Preparing locals 
     gen.DeclareLocal(typeof(Boolean)); 
     // Preparing labels 
     Label labelNoMatch = gen.DefineLabel(); 
     // Writing body 
     gen.Emit(OpCodes.Ldarg_0); 
     gen.Emit(OpCodes.Callvirt, getFromKeyMethod); 
     gen.Emit(OpCodes.Ldarg_1); 
     gen.Emit(OpCodes.Callvirt, getToKeyMethod); 
     gen.Emit(OpCodes.Ceq); 
     gen.Emit(OpCodes.Stloc_0); 
     gen.Emit(OpCodes.Ldloc_0); 
     gen.Emit(OpCodes.Brfalse_S, labelNoMatch); 
     gen.Emit(OpCodes.Ldarg_1); 
     gen.Emit(OpCodes.Ldarg_0); 


     foreach (var mapping in memberMappings) 
     { 
      var getFromValueMethod = fromType.GetMethod(
       string.Format("get_{0}", mapping.Key), 
       BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); 

      var setToValueMethod = toType.GetMethod(
       string.Format("set_{0}", mapping.Value), 
       BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); 

      gen.Emit(OpCodes.Callvirt, getFromValueMethod); 
      gen.Emit(OpCodes.Callvirt, setToValueMethod); 
     } 

     gen.MarkLabel(labelNoMatch); 
     gen.Emit(OpCodes.Ldloc_0); 
     gen.Emit(OpCodes.Ret); 


     return method; 
    } 

    public void Map (object fromInstance, object toInstance) 
    { 
     _mapper.Invoke(null, new[] { fromInstance, toInstance }); 
    } 


    public TypeMapper(Type fromType, Type toType, 
     KeyValuePair<string, string> keyMemberMap, 
     Dictionary<string, string> memberMappings) 
    { 
     _mapper = BuildMapper(fromType, toType, keyMemberMap, memberMappings); 
    } 

} 

답변

1
bound.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public).ToList() 
    .ForEach(s => 
     { 
      var prop = import.GetType().GetProperty(s.Name,BindingFlags.Public | BindingFlags.Instance); 
      if(prop != null) 
      { 
       prop.SetValue(import,s.GetValue(bound,null),null); 
      } 
     }); 

. 당신이 컬렉션에서 그것을하고 싶다면 그 방법을 만들고 myCollection.Select(o => MapProperties(o,mapType));을해라.

참고 :이 메서드는 현재 기존 개체를 사용하여 복사합니다. 형식을 제외하고 메서드를 사용할 수 있고 Activator.CreateInstance(type)을 호출하고이를 내 발췌의 가져 오기 값으로 설정합니다.

편집

Dynamic Methods

이 문서에서는 동적 객체의 전체 복사를 할 수있는 DynamicMethod를 생성하는 좋은 사례가있다. 그것은 반사 솔루션보다 훨씬 더 긴 셋업 시간을 가질 것이지만, 이후의 각각의 호출은 컴파일 된 것처럼 빠르게 될 것입니다.

편집

실제 예 :

DynamicMethod GetMapper(Type type1, Type type2) 
{ 
DynamicMethod method = new DynamicMethod("junk", type2, 
new Type[] { type1 }); 

ILGenerator il = method.GetILGenerator(); 

LocalBuilder obj0 = il.DeclareLocal(type2); //target 

// create object and store in local 0 
ConstructorInfo ctor = type2.GetConstructor(
    new Type[] { }); 
il.Emit(OpCodes.Newobj, ctor); 
il.Emit(OpCodes.Stloc_0); 


PropertyInfo[] properties = type1.GetProperties(BindingFlags.Instance 
| BindingFlags.Public | BindingFlags.FlattenHierarchy); 
foreach (PropertyInfo prop in properties) 
{ 
// local constructed object 
il.Emit(OpCodes.Ldloc_0); 

// load source argument 
il.Emit(OpCodes.Ldarg_0); 

// get property value 
il.EmitCall(OpCodes.Callvirt, type1.GetMethod(
    "get_" + prop.Name), null); 
il.EmitCall(OpCodes.Callvirt, type2.GetMethod(
    "set_" + prop.Name), null); 
} 

il.Emit(OpCodes.Ldloc_0); 
il.Emit(OpCodes.Ret); 
return method; 
} 

당신은 내가 매우 비슷한했다 GetMapper(sourceType,destinationType).Invoke(null,new [] { myObject});

+0

할 수 있어야, 그것은 (반사를 사용하여) 우리가 때 느린 것으로 판명 약간의 1000s를 고려하십시오. 여전히 +1 –

+0

유형이 동적으로 생성되는 경우 이것이 가장 가능성이 높습니다. 'Reflection.Emit'을 사용하여 팩토리 델리게이트를 생성 한 다음 실행하면 속도를 약간 높일 수 있습니다.하지만 정확히 할 경로는 확실하지 않습니다. 'Reflection.Emit'을 위해 MSDN을 살펴 보는 것이 좋습니다. 좋은 방향을 제시 할 수 있기 때문입니다. – Stephan

+0

이것은 Silverlight 질문 이었음을 잊었습니다. 내 두 번째 솔루션은 Silverlight에서 아마 작동하지 않을 것입니다. RIA와 마찬가지로 서버 측 작업으로도 가능하지만 순수 클라이언트 측으로는 작동하지 않을 수 있습니다. – Stephan