将一个对象映射到另一个对象的最佳实践

我的问题是,以最可维护的方式将一个对象映射到另一个对象的最佳方法是什么。 我无法改变我们获得的Dto对象设置为更规范化的方式,因此我需要创建一种方法将其映射到我们对象的实现。

以下示例代码显示了我需要发生的事情:

class Program { static void Main(string[] args) { var dto = new Dto(); dto.Items = new object[] { 1.00m, true, "Three" }; dto.ItemsNames = new[] { "One", "Two", "Three" }; var model = GetModel(dto); Console.WriteLine("One: {0}", model.One); Console.WriteLine("Two: {0}", model.Two); Console.WriteLine("Three: {0}", model.Three); Console.ReadLine(); } private static Model GetModel(Dto dto) { var result = new Model(); result.One = Convert.ToDecimal(dto.Items[Array.IndexOf(dto.ItemsNames, "One")]); result.Two = Convert.ToBoolean(dto.Items[Array.IndexOf(dto.ItemsNames, "Two")]); result.Three = dto.Items[Array.IndexOf(dto.ItemsNames, "Three")].ToString(); return result; } } class Dto { public object[] Items { get; set; } public string[] ItemsNames { get; set; } } class Model { public decimal One { get; set; } public bool Two { get; set; } public string Three { get; set; } } 

我认为如果我有某种mapper类可以接受模型对象propertyInfo,我要转换为的类型,以及我要提取的“itemname”,那会是多么美妙。 有没有人有任何建议让这个更干净?

谢谢!

我会选择AutoMapper ,一个开源和自由映射库,允许根据约定将一种类型映射到另一种类型(即映射具有相同名称和相同/派生/可转换类型的公共属性,以及许多其他智能类型)。 非常容易使用,会让你实现这样的目标:

 Model model = Mapper.Map(dto); 

不确定您的具体要求,但AutoMapper还支持自定义值解析器 ,这可以帮助您编写特定映射器的单个通用实现。

这是一个可能的generics实现,使用一点reflection(伪代码,现在没有VS):

 public class DtoMapper { Dictionary properties; public DtoMapper() { // Cache property infos var t = typeof(DtoType); properties = t.GetProperties().ToDictionary(p => p.Name, p => p); } public DtoType Map(Dto dto) { var instance = Activator.CreateInstance(typeOf(DtoType)); foreach(var p in properties) { p.SetProperty( instance, Convert.Type( p.PropertyType, dto.Items[Array.IndexOf(dto.ItemsNames, p.Name)]); return instance; } } 

用法:

 var mapper = new DtoMapper(); var modelInstance = mapper.Map(dto); 

创建映射器实例时这会很慢但以后会快得多。

 ///  /// map properties ///  ///  ///  private void MapProp(object sourceObj, object targetObj) { Type T1 = sourceObj.GetType(); Type T2 = targetObj.GetType(); PropertyInfo[] sourceProprties = T1.GetProperties(BindingFlags.Instance | BindingFlags.Public); PropertyInfo[] targetProprties = T2.GetProperties(BindingFlags.Instance | BindingFlags.Public); foreach (var sourceProp in sourceProprties) { object osourceVal = sourceProp.GetValue(sourceObj, null); int entIndex = Array.IndexOf(targetProprties, sourceProp); if (entIndex >= 0) { var targetProp = targetProprties[entIndex]; targetProp.SetValue(targetObj, osourceVal); } } }