Automapper 和 Nullable 引用类型提高 "needs to have a constructor with 0 args or only optional args"
Automapper and Nullable Reference Type raise "needs to have a constructor with 0 args or only optional args"
场景
我无法将 class 映射到 string
和可为 null 的引用类型 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);
解决方法
我找到了两个解决方法:
一个
如果我在 CreateMap 上指定 .ForCtorParam("author", o => o.MapFrom(k => "dummy"))
它会正常工作
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))
;
两个
添加一个 args 0 构造函数
public CreateSong() : base(string.Empty, string.Empty, null)
{
Author = string.Empty;
}
问题
为什么Automapper
可以映射title
、content
和tags
但不能映射author
字段?我怀疑它是否链接到可为空的引用类型。
它与可空引用类型无关。 Automapper is capable of mapping fields/properties to constructor parameters 基于名称,没有匹配 author
参数,因此原始映射失败。 IE。接下来将工作:
cfg.CreateMap<Song, CreateSong>()
.ForCtorParam("author", o => o.MapFrom(k => "dummy"));
另请注意,ForMember
调用实际上会被忽略。尝试将映射更改为:
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")) ;
你会发现它不会影响结果。
场景
我无法将 class 映射到 string
和可为 null 的引用类型 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);
解决方法
我找到了两个解决方法:
一个
如果我在 CreateMap 上指定 .ForCtorParam("author", o => o.MapFrom(k => "dummy"))
它会正常工作
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))
;
两个
添加一个 args 0 构造函数
public CreateSong() : base(string.Empty, string.Empty, null)
{
Author = string.Empty;
}
问题
为什么Automapper
可以映射title
、content
和tags
但不能映射author
字段?我怀疑它是否链接到可为空的引用类型。
它与可空引用类型无关。 Automapper is capable of mapping fields/properties to constructor parameters 基于名称,没有匹配 author
参数,因此原始映射失败。 IE。接下来将工作:
cfg.CreateMap<Song, CreateSong>()
.ForCtorParam("author", o => o.MapFrom(k => "dummy"));
另请注意,ForMember
调用实际上会被忽略。尝试将映射更改为:
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")) ;
你会发现它不会影响结果。