集合中对象到对象属性的映射
我创建一个(动态生成的类型)集合以在 silverlight 网格中显示,其中一个过程涉及创建一个导入(动态生成的类型)类型,然后将导入类型上的属性映射到(动态生成的类型)两种类型的集合共享一个 Id 属性来标识该项目(无论是在网格上还是在导入中),
即 类型绑定到网格
int Id {get; set}
string Foo {get;set;}
string FooFoo {get;set;}
并导入 ids 匹配的类型
int Id {get; set}
string Foo {get;set}
我想复制 foos.
将集合中的属性从一种类型映射到另一种类型的快速方法是什么?
编辑
这是最终的类型映射器实现,感谢Stephan,因为该功能仅在键成员相等时映射两种类型,通过代表成员名称的字典字符串定义的映射,适用于银光。
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);
}
}
Im creating a collection of (dynamically generated type) for display in a silverlight grid and one of the processes involves creating an import (dynamically generated type) type then mapping the properties on the import type to the collection of (dynamically generated type) both types share a Id property that identifies the item ( be it on the grid or in the import)
ie
type bound to grid
int Id {get; set}
string Foo {get;set;}
string FooFoo {get;set;}
and import the type
int Id {get; set}
string Foo {get;set}
where ids match i want to copy foos.
What is a fast way to map properties from the one type to another in a collection?
EDIT
Heres the final Typemapper implementation with thanks to Stephan, as a feature will only map the two types when the keymembers are equal, mappings defined via a dictionary string string representing the member names, works in 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);
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
这会将属性从一项映射到另一项。如果您想在集合中执行此操作,请将该方法设为一个方法并执行
myCollection.Select(o => MapProperties(o,mapType));
。注意:该方法当前使用现有对象并将其复制到其中。您可以使用除类型之外的方法,然后调用 Activator.CreateInstance(type) 并将其设置为我的代码片段的导入值。
编辑
动态方法
本文提供了一个生成
DynamicMethod
来执行动态对象深层复制的好示例。与反射解决方案相比,它的设置时间要长得多,但每个后续调用都会像编译一样快。编辑
实际示例:
您应该能够执行
GetMapper(sourceType,destinationType).Invoke(null,new [] { myObject});
That will map properties from one item to another. If you want to do it in a collection make that a method and do
myCollection.Select(o => MapProperties(o,mapType));
.Note: The method currently uses an existing object and copies into it. You could have your method except a type and then call
Activator.CreateInstance(type)
and set that to the value of import for my snippet.Edit
Dynamic Methods
This article has a good example of generating a
DynamicMethod
to do the deep copy of dynamic objects. It will have a much longer setup time then the reflection solution, but each subsequent call will be as fast as if compiled.Edit
Actual Example:
You should be able to do
GetMapper(sourceType,destinationType).Invoke(null,new [] { myObject});