【问题标题】:How to map an object with a custom constructor from a dynamic object with automapper如何使用 automapper 从动态对象映射具有自定义构造函数的对象
【发布时间】:2016-11-15 00:49:11
【问题描述】:

我正在测试 automapper 以查看它是否可以在其他项目中完成我需要的操作,因此我在控制台项目中制作了一些对象,虽然简化但应该满足我的需要:

public class Person
{
    public Person(List<Banco> bancos)
    {
        this._Bancos = bancos;
    }

    public int Id { get; set; }
    public string Nombre { get; set; }
    public DNI Dni { get; set; }
    private List<Banco> _Bancos;

    public List<Banco> Bancos
    {
        get { return _Bancos; }
    }

}

public class DNI
{
    private DNI() { }
    public DNI(DNI2 letra)
    {
        this._Letra = letra;
        Console.WriteLine("****DNI CONSTRUCTOR****");
    }

    public int Id { get; set; }
    public int PersonId { get; set; }
    public string number { get; set; }
    private DNI2 _Letra;

    public DNI2 Letra
    {
        get { return _Letra; }
    }

}

public class DNI2
{
    public int Id { get; set; }
    public int DNIId { get; set; }
    public string letra { get; set; }
}

public class Banco
{
    public int Id { get; set; }
    public string number { get; set; }
}

如您所见,对象PersonDNI 有一个自定义的协程函数,我将最后一个的默认无参数构造函数设置为私有。

现在,我需要使用来自动态对象的自定义构造函数来映射嵌套对象,所以我在同一个控制台项目中做了这个:

class Program
{
    static void Main(string[] args)
    {
        //OJO TODO: ¿Si un objeto dinamico tiene propiedades de varios tipos, es capaz de diferenciar a qué tipo pertenece cada prop?
        //¿qué pasa si un valor del dinamico es del tipo equivocado?
        var bancoConfig = new MapperConfiguration(cfg => cfg.CreateMissingTypeMaps = true);
        var DNI2Config = new MapperConfiguration(cfg => cfg.CreateMissingTypeMaps = true);
        DNI2Config.AssertConfigurationIsValid();
        var bancoMapper = bancoConfig.CreateMapper();
        var dni2Mapper = DNI2Config.CreateMapper();

        var dni2DBConfig = new MapperConfiguration(cfg =>
        {
            cfg.CreateMissingTypeMaps = true;
            cfg.RecognizePrefixes("DNI2");
        });
        var dni2DBMapper = dni2DBConfig.CreateMapper();

        var DNIConfig = new MapperConfiguration(cfg =>
        {
            cfg.CreateMap<dynamic, DNI>()
            .ConstructUsing(dyn => new DNI(dni2DBMapper.Map<DNI2>(dyn)));
            /*.ForMember(dest => dest.Id, opts => opts.MapFrom<int>(src => (int)(src as IDictionary<string, object>)["Id"]))
            .ForMember(dest => dest.number, opts => opts.MapFrom<string>(src => (string)(src as IDictionary<string, object>)["number"]))
            .ForMember(dest => dest.PersonId, opts => opts.MapFrom<int>(src => (int)(src as IDictionary<string, object>)["PersonId"]));*/
            /*cfg.CreateMap<IDictionary<string, object>, DNI>()
            .ConstructUsing(dyn => new DNI(dni2DBMapper.Map<DNI2>(dyn as dynamic)))
            .ForMember(dest => dest.Id, opts => opts.MapFrom<int>(src => (int)(src["Id"])))
            .ForMember(dest => dest.number, opts => opts.MapFrom<string>(src => (string)(src["number"])))
            .ForMember(dest => dest.PersonId, opts => opts.MapFrom<int>(src => (int)(src["PersonId"])));*/

            cfg.CreateMissingTypeMaps = true;
        });
        var dniMapper = DNIConfig.CreateMapper();

        dynamic d = new { Id = 0, number = "1234" };
        Banco banco = bancoMapper.Map<Banco>(d);
        Console.WriteLine("Banco: " + Environment.NewLine);
        Console.WriteLine(banco.Id + Environment.NewLine + banco.number);
        Console.ReadLine();

        d = new { Id = 1, DNIId = 0, letra = "a" };
        DNI2 dni2 = dni2Mapper.Map<DNI2>(d);
        Console.WriteLine("DNI2: " + Environment.NewLine);
        Console.WriteLine(dni2.Id + Environment.NewLine + dni2.DNIId + Environment.NewLine + dni2.letra);
        Console.ReadLine();

        d = new { Id = 2, PersonId = 5, number = "5678", DNI2Id = 2, DNIId = 2, letra = "b" };
        DNI2 d2 = dni2DBMapper.Map<DNI2>(d);
        DNI dni = dniMapper.Map<DNI>(d);
        Console.WriteLine("DNI: " + Environment.NewLine);
        Console.WriteLine(dni.Id + Environment.NewLine + dni.PersonId + Environment.NewLine + dni.number + Environment.NewLine);
        Console.WriteLine("dni.dni2: "+dni.Letra.Id + Environment.NewLine + dni.Letra.DNIId + Environment.NewLine + dni.Letra.letra);
        Console.ReadLine();
    }
}

这在控制台中给出了这个结果:

Banco:

0
1234

DNI2:

1
0
a

****DNI CONSTRUCTOR****
DNI:

2
5
5678

dni.dni2: 0
0

所以,它只是创建DNI 对象并设置成员,它通过公共构造函数...但即使它通过构造函数它也不会设置DNI2 属性。
如果我在DNI配置中加入动态行:

        var DNIConfig = new MapperConfiguration(cfg =>
        {
            cfg.CreateMap<dynamic, DNI>()
            .ConstructUsing(dyn => new DNI(dni2DBMapper.Map<DNI2>(dyn)));
            /*.ForMember(dest => dest.Id, opts => opts.MapFrom<int>(src => (int)(src as IDictionary<string, object>)["Id"]))
            .ForMember(dest => dest.number, opts => opts.MapFrom<string>(src => (string)(src as IDictionary<string, object>)["number"]))
            .ForMember(dest => dest.PersonId, opts => opts.MapFrom<int>(src => (int)(src as IDictionary<string, object>)["PersonId"]));*/
            /*cfg.CreateMap<IDictionary<string, object>, DNI>()
            .ConstructUsing(dyn => new DNI(dni2DBMapper.Map<DNI2>(dyn as dynamic)))
            .ForMember(dest => dest.Id, opts => opts.MapFrom<int>(src => (int)(src["Id"])))
            .ForMember(dest => dest.number, opts => opts.MapFrom<string>(src => (string)(src["number"])))
            .ForMember(dest => dest.PersonId, opts => opts.MapFrom<int>(src => (int)(src["PersonId"])));*/

            //cfg.CreateMissingTypeMaps = true;
        });

...所以它没有使其动态的配置,结果是:

Banco:

0
1234

DNI2:

1
0
a

****DNI CONSTRUCTOR****
DNI:

0
0


dni.dni2: 2
2
b

配置中的注释行只是我尝试过的一部分,包括两天在这里搜索和google。
似乎程序告诉我:你从动态映射它你使用自定义构造函数,你不能同时做,糟透了。

对我来说最有趣的部分是:使用第一个配置,它不是映射DNI2 对象,而是使用构造函数映射DNI 对象(该行在控制台上),但它没有参数所需的对象,所以它使用构造函数没有所需的参数 O_o
老实说,我知道我是个业余爱好者,但我一直认为,即使使用反射,也不能在没有任何必需参数的情况下使用构造函数(也不能使用任何其他方法)。

那么:有没有办法用 automapper 从动态对象映射嵌套对象和自定义构造函数?

【问题讨论】:

    标签: c# dynamic automapper


    【解决方案1】:

    我已经找到了解决办法:

            var DNIDynConfig = new MapperConfiguration(cfg => cfg.CreateMissingTypeMaps = true);
            var dniDynMapper = DNIDynConfig.CreateMapper();
            var DNIConfig = new MapperConfiguration(cfg =>
            {
                cfg.CreateMap<dynamic, DNI>()
                .ConstructUsing(dyn => new DNI(dni2DBMapper.Map<DNI2>(dyn)))
                .AfterMap((src, dest) =>
                {
                    dniDynMapper.Map(src, dest, typeof(object), typeof(DNI));
                });
            });
    

    我不太喜欢它,因为它似乎必须映射对象两次,但它确实有效。不过,如果有人能提供更好的东西,我会很感激。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-05-26
      • 1970-01-01
      • 2016-10-14
      • 2011-02-24
      • 1970-01-01
      • 1970-01-01
      • 2016-06-15
      相关资源
      最近更新 更多