我正在设置一个automapper配置文件来将Revit元素(从它们的api)映射到一些自定义元素。他们的API得到了循环引用(1个元素=> n个参数,1个参数=> 1个元素)我调用了PreserveReference()方法。但它似乎没有用,因为我有一个StackOverflowException。那么,我想知道PreserveReference是如何工作的?我可以指定一个属性来检查相等性而不是使用引用吗?
public class Element
{
public int Id { get; set; }
public List<Parameter> Parameters { get; set; }
public override bool Equals(object obj)
{
return obj is Element element && Id == element.Id;
}
public override int GetHashCode()
{
// ReSharper disable once NonReadonlyMemberInGetHashCode
return Id;
}
}
public class Parameter
{
public int Id { get; set; }
public Definition Definition { get; set; }
public Element Element { get; set; }
}
profile.CreateMap<Element, Models.Element>()
.ForMember(element => element.Id, expression => expression.MapFrom(element => element.Id.IntegerValue))
.IncludeAllDerived()
.PreserveReferences();
profile.CreateMap<Parameter, Models.Parameter>()
.ForMember(parameter => parameter.Id, expression => expression.MapFrom(parameter => parameter.Id.IntegerValue))
.IncludeAllDerived()
.PreserveReferences();
我找到了一种方法来获得我想要的东西。我不得不访问这样的私有财产:
public static T GetSource<T>(this ContextCacheKey contextCacheKey)
{
var source = (T)typeof(ContextCacheKey).GetField("_source", BindingFlags.NonPublic | BindingFlags.GetField | BindingFlags.Instance)?.GetValue(contextCacheKey);
return source;
}
public class ElementConverter : IValueConverter<Element, Models.Element>
{
public Models.Element Convert(Element sourceMember, ResolutionContext context)
{
var a = (Models.Element)context.InstanceCache.FirstOrDefault(kvp => kvp.Key.GetSource<Element>().Id.Equals(sourceMember.Id)).Value ?? context.Mapper.Map<Models.Element>(sourceMember);
return a;
}
}
一个简单的解决方案是在ContextCacheKey struc中公开Source和DestinationType:
public struct ContextCacheKey : IEquatable<ContextCacheKey>
{
public static bool operator ==(ContextCacheKey left, ContextCacheKey right) => left.Equals(right);
public static bool operator !=(ContextCacheKey left, ContextCacheKey right) => !left.Equals(right);
public readonly object _source;
public readonly Type _destinationType;
public ContextCacheKey(object source, Type destinationType)
{
_source = source;
_destinationType = destinationType;
}
public override int GetHashCode() => HashCodeCombiner.Combine(_source, _destinationType);
public bool Equals(ContextCacheKey other) =>
_source == other._source && _destinationType == other._destinationType;
public override bool Equals(object other) =>
other is ContextCacheKey && Equals((ContextCacheKey)other);
}