我在AutoMapper中遇到一个自定义ITypeConverter的问题,关于循环引用。请参考以下示例:假设House
中包含List<Person>
,Persons
中的每一个都属于House
。我们可以这样建模:
public class House
{
public int PropertyA { get; set; }
public string PropertyB { get; set; }
public List<Person> People { get; set; }
}
public class Person
{
public int PropertyA { get; set; }
public string PropertyB { get; set; }
public House House { get; set; }
}
也许我们有一些看起来像这样的DTO:
public class HouseDto
{
public string PropertyB { get; set; }
public List<PersonDto> People { get; set; }
}
public class PersonDto
{
public string PropertyB { get; set; }
public HouseDto House { get;set; }
}
由于AutoMapper的基于约定的映射非常慢,我选择使用自定义类型转换器以避免AutoMapper使用的所有反射。所以我有两个这样的转换器:
public class HouseConverter : ITypeConverter<House, HouseDto>
{
private readonly IMapper _mapper;
public HouseConverter(IMapper mapper)
{
_mapper = mapper;
}
public HouseDto Convert(House source, HouseDto destination, ResolutionContext context)
{
if (source == null) return null;
destination = destination ?? new HouseDto();
destination.PropertyB = source.PropertyB;
destination.People = _mapper.Map<List<PersonDto>>(source.People);
return destination;
}
}
public class PersonConverter : ITypeConverter<Person, PersonDto>
{
private readonly IMapper _mapper;
public PersonConverter(IMapper mapper)
{
_mapper = mapper;
}
public PersoneDto Convert(Person source, PersonDto destination, ResolutionContext context)
{
if (source == null) return null;
destination = destination ?? new PersonDto();
destination.PropertyB = source.PropertyB;
destination.House = _mapper.Map<HouseDto>(source.House);
return destination;
}
}
显然这会导致StackOverflowException,因为关系会创建循环引用。为了避免这种情况,AutoMapper具有MaxDepth选项,您可以在使用内置映射方法时使用,但是当您开始使用自己的转换器时,此功能显然会丢失。我想了解一下在自定义转换器中实现此功能的正确方法。
问题在于:在AutoMapper v5.0之前,自定义转换器可以访问包含MaxDepth值的ResolutionContext,看起来它还包含当前深度好。这将允许我检测达到深度限制并停止任何进一步的递归。但是,随着5.0中ResolutionContext的更改,我无法找到访问MaxDepth或当前深度的任何方法。 这些值是否仍然可以以某种方式提供给ITypeConverter,或者我们现在希望自己实现这些值?在线文档并没有提供有关此特定用法的大量详细信息。