Scenario
I can't map a class with string
and nullable reference type enabled
#r "nuget:AutoFixture/4.17.0"
#r "nuget:AutoMapper/11.0.1"
using AutoFixture;
using AutoMapper;
class Song
{
public int Id { get; set; }
public string Title { get; set; }
public string Content { get; set; }
public IEnumerable<Tag>? Tags { get; set; }
public Song()
{
Title = string.Empty;
Content = string.Empty;
}
}
class Tag
{
public int Id { get; set; }
public string Title { get; set; }
public string Color { get; set; }
public Tag()
{
Title = string.Empty;
Color = string.Empty;
}
}
class DetailSong
{
public string Title { get; set; }
public string Content { get; set; }
public IEnumerable<int>? Tags { get; set; }
public DetailSong(string title, string content, IEnumerable<int>? tags)
{
Title = title;
Content = content;
Tags = tags;
}
}
class CreateSong : DetailSong
{
public string Author { get; set; }
public CreateSong(string author, string title, string content, IEnumerable<int>? tags) :
base(title, content, tags)
{
Author = author;
}
}
var config = new MapperConfiguration(cfg =>
{
cfg.CreateMap<Tag, int>()
.ConstructUsing(p => p.Id)
;
cfg.CreateMap<Song, CreateSong>()
.ForMember(p => p.Author, o => o.MapFrom(k => "dummy"))
.ForMember(p => p.Content, o => o.MapFrom(k => k.Content))
.ForMember(p => p.Title, o => o.MapFrom(k => k.Title))
;
});
var mapper = config.CreateMapper();
Fixture fixture = new Fixture();
var s = fixture.Create<Song>();
// throw needs to have a constructor with 0 args or only optional args. Validate your configuration for details. (Parameter 'type')
var m = mapper.Map<CreateSong>(s);
Workaround
I found two workaround:
One
If I specify .ForCtorParam("author", o => o.MapFrom(k => "dummy"))
on CreateMap it work correctly
cfg.CreateMap<Song, CreateSong>()
.ForCtorParam("author", o => o.MapFrom(k => "dummy")) // <--------
.ForMember(p => p.Content, o => o.MapFrom(k => k.Content))
.ForMember(p => p.Title, o => o.MapFrom(k => k.Title))
;
Two
Add a args 0 ctor
public CreateSong() : base(string.Empty, string.Empty, null)
{
Author = string.Empty;
}
Question
Why Automapper
can map title
, content
and tags
but not the author
field? I suspect is it linked to nullable reference type.
CodePudding user response:
It is not related to the nullable reference types. Automapper is capable of mapping fields/properties to constructor parameters based on names and there is nothing to match author
parameter so the original mapping fails. I.e. next will work:
cfg.CreateMap<Song, CreateSong>()
.ForCtorParam("author", o => o.MapFrom(k => "dummy"));
Also note that ForMember
calls are actually ignored. Try changing mapping to:
cfg.CreateMap<Song, CreateSong>()
.ForCtorParam("author", o => o.MapFrom(k => "dummy"))
.ForMember(p => p.Content, o => o.MapFrom(k => k.Content "_Test"))
.ForMember(p => p.Title, o => o.MapFrom(k => k.Title "_Test")) ;
And you will see that it does not affect result.