如何按属性保存引用

时间:2019-04-19 09:36:38

标签: c# 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();

1 个答案:

答案 0 :(得分:0)

我找到一种获取我想要的东西的方法。我必须访问像这样的私有财产:

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);
}