我在使这个工作正常时遇到了一些麻烦.我有两节课:
public class TestClassA
{
public int? NullableIntProperty { get; set; }
}
public class TestClassB
{
public int NotNullableIntProperty { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
然后我设置以下映射:
cfg.CreateMap<TestClassA, TestClassB>()
.ForMember(dest => dest.NotNullableIntProperty,
opt => opt.MapFrom(src => src.NullableIntProperty));
cfg.CreateMap<TestClassA, TestClassA>()
.ForMember(dest => dest.NullableIntProperty,
opt => opt.MapFrom(src => src.NullableIntProperty));
cfg.CreateMap<TestClassB, TestClassA>()
.ForMember(dest => dest.NullableIntProperty,
opt => opt.MapFrom(src => src.NotNullableIntProperty));
cfg.CreateMap<TestClassB, TestClassB>()
.ForMember(dest => dest.NotNullableIntProperty,
opt => opt.MapFrom(src => src.NotNullableIntProperty));
Run Code Online (Sandbox Code Playgroud)
我现在已经设置了四个映射,并将测试以下场景:
int? => int
int => int?
int => int
int? => int?
Run Code Online (Sandbox Code Playgroud)
在测试类中,我然后使用这样的映射:
var testQueryableDest = testQueryableSrc.ProjectTo<...>(_mapper.ConfigurationProvider);
Run Code Online (Sandbox Code Playgroud)
我期望在这个阶段不能工作的唯一预测是TestClassA => TestClassB,因为我可以看到AutoMapper可能不知道如何处理int?值的情况null.果然,情况确实如此.所以我设置了这样的映射int? => int:
cfg.CreateMap<int?, int>()
.ProjectUsing(src => src ?? default(int));
Run Code Online (Sandbox Code Playgroud)
事情变得奇怪了.只要我添加此映射,映射TestClassB => TestClassB就会失败甚至创建.它给出了以下错误消息:
类型'System.Int32'的表达式不能用于赋值类型'System.Nullable`1 [System.Int32]'
我发现这条消息非常奇怪,因为TestClassB根本没有int?它.那么这里发生了什么?我觉得我必须误解一下AutoMapper如何处理这些预测.我意识到各种代码可能很难拼凑起来所以这里是整个测试类供参考:
[TestClass]
public class BasicTests
{
private readonly IMapper _mapper;
public BasicTests()
{
var config = new MapperConfiguration(cfg =>
{
cfg.CreateMap<int?, int>()
.ProjectUsing(src => src ?? default(int));
cfg.CreateMap<TestClassA, TestClassB>()
.ForMember(dest => dest.IntProperty, opt => opt.MapFrom(src => src.NullableIntProperty));
cfg.CreateMap<TestClassA, TestClassA>()
.ForMember(dest => dest.NullableIntProperty, opt => opt.MapFrom(src => src.NullableIntProperty));
cfg.CreateMap<TestClassB, TestClassA>()
.ForMember(dest => dest.NullableIntProperty, opt => opt.MapFrom(src => src.IntProperty));
cfg.CreateMap<TestClassB, TestClassB>()
.ForMember(dest => dest.IntProperty, opt => opt.MapFrom(src => src.IntProperty));
});
_mapper = new Mapper(config);
}
[TestMethod]
public void CanMapNullableIntToInt()
{
var testQueryableSource = new List<TestClassA>
{
new TestClassA
{
NullableIntProperty = null
}
}.AsQueryable();
var testQueryableDestination = testQueryableSource.ProjectTo<TestClassB>(_mapper.ConfigurationProvider);
}
[TestMethod]
public void CanMapNullableIntToNullableInt()
{
var testQueryableSource = new List<TestClassA>
{
new TestClassA
{
NullableIntProperty = null
}
}.AsQueryable();
var testQueryableDestination = testQueryableSource.ProjectTo<TestClassA>(_mapper.ConfigurationProvider);
}
[TestMethod]
public void CanMapIntToNullableInt()
{
var testQueryableSource = new List<TestClassB>
{
new TestClassB
{
IntProperty = 0
}
}.AsQueryable();
var testQueryableDestination = testQueryableSource.ProjectTo<TestClassA>(_mapper.ConfigurationProvider);
}
[TestMethod]
public void CanMapIntToInt()
{
var testQueryableSource = new List<TestClassB>
{
new TestClassB
{
IntProperty = 0
}
}.AsQueryable();
var testQueryableDestination = testQueryableSource.ProjectTo<TestClassB>(_mapper.ConfigurationProvider);
}
}
Run Code Online (Sandbox Code Playgroud)
我\xe2\x80\x99ve发现重现这种情况的最短方法如下:
\n\nvar config = new MapperConfiguration(cfg =>\n{\n cfg.CreateMap<int?, int>().ProjectUsing(x => x ?? default(int));\n cfg.CreateMap<TestClassA, TestClassA>()\n .ForMember(a => a.NullableIntPropety, o => o.MapFrom(a => a.NullableIntProperty));\n}\nRun Code Online (Sandbox Code Playgroud)\n\n在我看来,AutoMapper 正在尝试int? => int在这里使用映射器,尽管这里将使用更明显的基于身份的映射。
由于 everyint也是有效的int?,因此 AutoMapper尝试在此处使用int? => int映射器并将结果分配给该int?成员。但似乎在解决该分配时,在幕后某些东西无法正确工作,因此出现了异常。
解决这个问题的方法似乎是添加另一个映射,即身份映射int? => int?:
cfg.CreateMap<int?, int?>().ProjectUsing(x => x);\nRun Code Online (Sandbox Code Playgroud)\n\n然后,将使用此映射,并且不会发生异常(并且该映射也可以在所有示例中正常工作\xe2\x80\x94)。
\n\n这个问题似乎存在于当前的 AutoMapper 5.1.x 版本上(当前是 5.1.1)。好消息是,它已经得到修复。如果您尝试myget feed中的当前 5.2 alpha ,那么代码可以正常工作,没有任何问题。
\n\n自 5.1.1 版本以来,代码库已经做出了相当多的贡献,对可空映射进行了多个修复(例如this和this拉取请求)。我认为其中一项更改已经解决了这个问题。
\n\n最有可能的是 Pull request #1672,它只是为了删除不需要的代码,但显然也修复了问题 1664,该问题是关于 AutoMapper 显然优先考虑可空源映射而不是不可空源,即使正在映射不可空源。这听起来很像你所经历过的这个问题。
\n\n因此,目前,您可以添加上述解决方法以将类型映射到自身或使用 alpha 版本,同时我们等待 5.2 发布。
\n