代码之家  ›  专栏  ›  技术社区  ›  almog.ori

集合中的对象到对象属性映射

  •  0
  • almog.ori  · 技术社区  · 15 年前

    我正在创建一个(动态生成的类型)集合以在Silverlight网格中显示,其中一个过程涉及创建导入(动态生成的类型)类型,然后将导入类型上的属性映射到(动态生成的类型)两个类型的集合,这两个类型共享一个标识该项的ID属性(在GRI上是它)。d或进口)

    工业工程 绑定到网格的类型

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

    并导入类型

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

    在ID匹配的地方,我要复制foos。

    在集合中,将属性从一种类型映射到另一种类型的快速方法是什么?

    编辑

    这里是最后的typemapper实现,多亏了stephan,因为只有当keymembers相等时,功能才会映射这两种类型,映射是通过表示成员名称的字典字符串字符串定义的, 在Silverlight中工作 .

    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 回复  |  直到 15 年前
        1
  •  1
  •   Stephan    15 年前
    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) 并将其设置为我的代码段的import值。

    编辑

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