用于双向映射的简单约定自动映射(来自/来自ViewModels的实体)

更新:这个东西已经演变成一个很好的项目,请访问http://valueinjecter.codeplex.com


检查一下,我刚写了一个简单的自动播放器,它从属性中获取具有相同名称和类型的一个对象的值并将其放入另一个对象中,并且可以为您可能需要的每种类型添加exception(ifs,switch)

那么告诉我你怎么看?

我这样做了所以我可以这样做:

Product –> ProductDTO ProductDTO –> Product 

它是如何开始的:

我在Dropsow的Inputs / Dto / ViewModels中使用“object”类型,因为我向html发送了一个IEnumerable ,我收到一个选定键的字符串数组

  public void Map(object a, object b) { var pp = a.GetType().GetProperties(); foreach (var pa in pp) { var value = pa.GetValue(a, null); // property with the same name in b var pb = b.GetType().GetProperty(pa.Name); if (pb == null) { //no such property in b continue; } if (pa.PropertyType == pb.PropertyType) { pb.SetValue(b, value, null); } } } 

更新:真实用法:
构建方法(输入= Dto):

  public static TI BuildInput(this T entity) where TI: class, new() { var input = new TI(); input = Map(entity, input) as TI; return input; } public static T BuildEntity(this TI input) where T : class, new() where TR : IBaseAdvanceService { var id = (long)input.GetType().GetProperty("Id").GetValue(input, null); var entity = LocatorConfigurator.Resolve().Get(id) ?? new T(); entity = Map(input, entity) as T; return entity; } public static TI RebuildInput(this TI input) where T: class, new() where TR : IBaseAdvanceService where TI : class, new() { return input.BuildEntity().BuildInput(); } 

在控制器中:

  public ActionResult Create() { return View(new Organisation().BuildInput()); } [AcceptVerbs(HttpVerbs.Post)] public ActionResult Create(OrganisationInput o) { if (!ModelState.IsValid) { return View(o.RebuildInput()); } organisationService.SaveOrUpdate(o.BuildEntity()); return RedirectToAction("Index"); } 

真正的Map方法

 public static object Map(object a, object b) { var lookups = GetLookups(); var propertyInfos = a.GetType().GetProperties(); foreach (var pa in propertyInfos) { var value = pa.GetValue(a, null); // property with the same name in b var pb = b.GetType().GetProperty(pa.Name); if (pb == null) { continue; } if (pa.PropertyType == pb.PropertyType) { pb.SetValue(b, value, null); } else if (lookups.Contains(pa.Name) && pa.PropertyType == typeof(LookupItem)) { pb.SetValue(b, (pa.GetValue(a, null) as LookupItem).GetSelectList(pa.Name), null); } else if (lookups.Contains(pa.Name) && pa.PropertyType == typeof(object)) { pb.SetValue(b, pa.GetValue(a, null).ReadSelectItemValue(), null); } else if (pa.PropertyType == typeof(long) && pb.PropertyType == typeof(Organisation)) { pb.SetValue(b, pa.GetValue(a).ReadOrganisationId(), null); } else if (pa.PropertyType == typeof(Organisation) && pb.PropertyType == typeof(long)) { pb.SetValue(b, pa.GetValue(a).Id, null); } } return b; } 

您可能想要添加的一件事是缓存reflection位。 如果您将对象映射两次,则可能不希望再次查找所有reflection内容。 此外,像GetValue和SetValue这样的东西很慢,我切换到后期委托+ Reflection.Emit来加快速度。

只需使用AutoMapper 。 这很好,但它会成长为一个迷你项目。

AM(真正的)所做的一些事情是:

  • 如果您具有无法映射到的属性,则报告
  • 展平物体
  • 提供钩子供您自定义某些方面,而不是在一个大的switch语句中
  • 将Expression.Compile用于perf原因而不是直接reflection

但它肯定是一个有趣的空间,而自动映射的想法肯定是有用的。

有点像DI在15或33行与NInject或其朋友 – 酷,但为什么?

我认为你已经阅读了有关Jimmy博客上双向映射的文章和评论 ?

只是一个想法:

人们可能想知道抽象的重点是抽象是如此容易映射到被抽象的。

您可以为您可能需要的每种类型添加例外(ifs,switch)

你不打算这样做。 认真。 作用于对象类型的case语句是糟糕的OOP样式。 我的意思是,非常糟糕。 就像在你的肚子里喝伏特加酒一样开车。 它可能会工作一段时间,但最终你会遇到麻烦。

好吧Jimmy告诉你不要使用AutoMapper ……但我打赌他的意思是别的。 现在,你发明了一些不同的东西 – 让吉米开心的事吗? ;-)不,你刚刚制作了自己的半卷AutoMapper。 吉米告诉你不要用它! 😉

所以这是我的建议:忽略吉米所说的,只想自己……并使用AutoMapper 😉