Automapper与ImmutableList

huangapple go评论55阅读模式
英文:

Automapper with immutablelist

问题

在Source类中,我有一个IEnumerable<T>属性。在目标类中,构造函数接受IEnumerable<T>并将其转换为IImmutableList<T>,然后赋值给一个IEnumerable<T>属性。

以下是来自.Net 7.0中program.cs的代码副本:

// 复制并粘贴到.Net 7的Program.cs中应该可以工作。
using AutoMapper;
using System.Collections.Immutable;

var mapperConfiguration = new MapperConfiguration(cfg =&gt; {
    cfg.CreateMap&lt;ClassSource, ClassDestination&gt;()
    .ConstructUsing(m =&gt; new ClassDestination(m.Nums));
    });

var mapper = mapperConfiguration.CreateMapper();

var classSource = new ClassSource();

var classDestination = mapper.Map&lt;ClassDestination&gt;(classSource);

Console.WriteLine(classDestination.Nums.Count());

public class ClassSource
{
    public IEnumerable&lt;int&gt; Nums { get; init; } = new List&lt;int&gt; { 1, 2, 3, 4, 5 };
}

public class ClassDestination
{
    public IEnumerable&lt;int&gt; Nums {get;}
    public ClassDestination(IEnumerable&lt;int&gt; ints)
    {
        //Nums = ints.ToList(); // 这个可以工作
        Nums = ints.ToImmutableList(); // 这个会引发异常
    }
}

映射失败,报错为:AutoMapper.AutoMapperMappingException: '错误映射类型。'

如何解决这个问题?

英文:

In Source class, I have IEnumurable<T> Property. In the dest class, constructor takes the IEnumurable<T> and converts to IImmutableList<T> and assigns to a IEnumurable<T> property.

Here is the code copied from program.cs in .Net 7.0:

// Copy and Paste to Program.cs in .Net 7 should work.
using AutoMapper;
using System.Collections.Immutable;

var mapperConfiguration = new MapperConfiguration(cfg =&gt; {
    cfg.CreateMap&lt;ClassSource, ClassDestination&gt;()
    .ConstructUsing(m =&gt; new ClassDestination(m.Nums));
    });

var mapper = mapperConfiguration.CreateMapper();

var classSource = new ClassSource();

var classDestination = mapper.Map&lt;ClassDestination&gt;(classSource);

Console.WriteLine(classDestination.Nums.Count());

public class ClassSource
{
    public IEnumerable&lt;int&gt; Nums { get; init; } = new List&lt;int&gt; { 1, 2, 3, 4, 5 };
}

public class ClassDestination
{
    public IEnumerable&lt;int&gt; Nums {get;}
    public ClassDestination(IEnumerable&lt;int&gt; ints)
    {
        //Nums = ints.ToList(); // This works
        Nums = ints.ToImmutableList(); // This throws exception
    }
}

Mapping fails with: AutoMapper.AutoMapperMappingException: 'Error mapping types.'

How can this be solved?

答案1

得分: 2

如果您让代码运行,将会出现完整的错误消息:

未处理的异常。AutoMapper.AutoMapperMappingException:映射类型错误。

映射类型:
ClassSource -&gt; ClassDestination
ClassSource -&gt; ClassDestination

类型映射配置:
ClassSource -&gt; ClassDestination
ClassSource -&gt; ClassDestination

目标成员:
Nums

 ---&gt; System.NotSupportedException:不支持指定的方法。
   在 System.Collections.Immutable.ImmutableList`1.System.Collections.Generic.ICollection&lt;T&gt;.Clear()
   在 lambda_method1(Closure, Object, ClassDestination, ResolutionContext)
   --- 内部异常堆栈跟踪的末尾 ---
   在 lambda_method1(Closure, Object, ClassDestination, ResolutionContext)
   在 Program.&lt;Main&gt;$(String[] args)
命令由信号6终止

正如您所看到的,它试图调用目标属性 Nums 中不可变列表的 .Clear() 方法,从而引发了 NotSupportedException 异常。

因为您已经通过构造函数初始化了列表,如果需要使用 ConstructUsing(),您应该明确忽略这个成员,通过在映射配置文件中添加相应的 .Ignore() 调用:

var mapperConfiguration = new MapperConfiguration(cfg =&gt;#
{
    cfg.CreateMap&lt;ClassSource, ClassDestination&gt;()
        .ForMember(m =&gt; m.Nums, conf =&gt; conf.Ignore())
        .ConstructUsing(m =&gt; new ClassDestination(m.Nums));
});

如果在调用构造函数之后,您的目标类已经完全初始化,您应该改为使用 .ConvertUsing()

var mapperConfiguration = new MapperConfiguration(cfg =&gt;#
{
    cfg.CreateMap&lt;ClassSource, ClassDestination&gt;()
        .ConvertUsing(m =&gt; new ClassDestination(m.Nums));
});
英文:

If you let the code run, the full error message is:

Unhandled exception. AutoMapper.AutoMapperMappingException: Error mapping types.

Mapping types:
ClassSource -&gt; ClassDestination
ClassSource -&gt; ClassDestination

Type Map configuration:
ClassSource -&gt; ClassDestination
ClassSource -&gt; ClassDestination

Destination Member:
Nums

 ---&gt; System.NotSupportedException: Specified method is not supported.
   at System.Collections.Immutable.ImmutableList`1.System.Collections.Generic.ICollection&lt;T&gt;.Clear()
   at lambda_method1(Closure, Object, ClassDestination, ResolutionContext)
   --- End of inner exception stack trace ---
   at lambda_method1(Closure, Object, ClassDestination, ResolutionContext)
   at Program.&lt;Main&gt;$(String[] args)
Command terminated by signal 6

As you can see, it tries to call the method .Clear() of the immutable list in the target property Nums, which throws the NotSupportedException.

Because you already initialize the list through the constructor, you should explicitly ignore this member by adding the corresponding .Ignore() call to your mapping profile if you need to use ConstructUsing():

var mapperConfiguration = new MapperConfiguration(cfg =&gt;#
{
    cfg.CreateMap&lt;ClassSource, ClassDestination&gt;()
        .ForMember(m =&gt; m.Nums, conf =&gt; conf.Ignore())
        .ConstructUsing(m =&gt; new ClassDestination(m.Nums));
});

If your target class is already fully initialized after calling the constructor, you should instead use .ConvertUsing():

var mapperConfiguration = new MapperConfiguration(cfg =&gt;#
{
    cfg.CreateMap&lt;ClassSource, ClassDestination&gt;()
        .ConvertUsing(m =&gt; new ClassDestination(m.Nums));
});

huangapple
  • 本文由 发表于 2023年6月5日 22:14:21
  • 转载请务必保留本文链接:https://go.coder-hub.com/76407337.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定