将一个对象映射到另一个对象的最佳做法[英] Best Practices for mapping one object to another

本文是小编为大家收集整理的关于将一个对象映射到另一个对象的最佳做法的处理/解决方法,可以参考本文帮助大家快速定位并解决问题,中文翻译不准确的可切换到English标签页查看源文。

问题描述

我的问题是,以最可维护的方式将一个对象映射到另一个对象的最佳方法是什么.我无法更改设置我们要获得的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; }
}

我认为,如果我有某种类型的映射类别的类别,这些类别会吸引模型对象PropertyInfo,我要转换为的类型以及我想拉出的" itemName".有人有任何建议以使这个更清洁吗?

谢谢!

推荐答案

我会选择 automapper ,一个开源源和免费的映射库,允许将一种类型映射到另一个基于约定(即具有相同名称和相同/派生/可转换类型的公共属性,以及许多其他智能者).非常易于使用,可以让您实现这样的目标:

Model model = Mapper.Map<Model>(dto);

不确定您的具体要求,但AutomApper还支持自定义价值分辨率,它应该帮助您编写特定映射器的单一通用实现.

其他推荐答案

这是使用一些反射的可能的通用实现(伪代码,现在没有VS):

public class DtoMapper<DtoType>
{
    Dictionary<string,PropertyInfo> 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<Model>();
var modelInstance = mapper.Map(dto);

当您创建映射器实例时,这将很慢,但是以后更快.

其他推荐答案

efran Cobisi使用自动映射器的建议是一个很好的建议.我已经使用了自动映射器一段时间了,它运行良好,直到我找到更快的替代方案, mappster .

给出了一个较大的列表或iEnumerable,Mapter优于自动映射器.我在某个地方找到了一个基准,显示映射的速度是6倍,但我再也找不到了.您可以查找它,然后,如果它适合您,请使用Mopter.

本文地址:https://www.itbaoku.cn/post/627771.html

问题描述

My question is, what is the best way I can map one object to another in the most maintainable manner. I cannot change the way the Dto object that we are getting is setup to be more normalized so I need to create a way to map this to our implementation of their object.

Here is example code to show what I need to happen:

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

I think what would be great is if I had some sort of mapper class that would take in the model objects propertyInfo, the type I want to convert to, and the "itemname" I want to pull out. Does anyone have any suggestions to make this cleaner?

Thanks!

推荐答案

I would opt for AutoMapper, an open source and free mapping library which allows to map one type into another, based on conventions (i.e. map public properties with the same names and same/derived/convertible types, along with many other smart ones). Very easy to use, will let you achieve something like this:

Model model = Mapper.Map<Model>(dto);

Not sure about your specific requirements, but AutoMapper also supports custom value resolvers, which should help you writing a single, generic implementation of your particular mapper.

其他推荐答案

This is a possible generic implementation using a bit of reflection (pseudo-code, don't have VS now):

public class DtoMapper<DtoType>
{
    Dictionary<string,PropertyInfo> 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;
        }
    }

Usage:

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

This will be slow when you create the mapper instance but much faster later.

其他推荐答案

Efran Cobisi's suggestion of using an Auto Mapper is a good one. I have used Auto Mapper for a while and it worked well, until I found the much faster alternative, Mapster.

Given a large list or IEnumerable, Mapster outperforms Auto Mapper. I found a benchmark somewhere that showed Mapster being 6 times as fast, but I could not find it again. You could look it up and then, if it is suits you, use Mapster.