如何映射多个源成员,以便propertyMap.SourceMembers产生这些多个源成员?

时间:2018-11-10 11:37:07

标签: c# automapper

我想通过遍历所有映射的属性来重用c#Automapper的初始化映射(使用版本6.2.2)。

假设我有以下内容:

public class Person
{
    public int Id { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

public class PersonDto
{
    public int Id { get; set; }
    public string FullName { get; set; }
}

AutoMapper.Mapper.Initialize(cfg =>
{
    cfg.CreateMap<Person, PersonDto>()
        .ForMember(dest => dest.FullName, 
                    opt => opt.MapFrom(src => src.FirstName + " " + src.LastName));
};

Id的循环行为符合预期:

var map = AutoMapper.Mapper.Configuration.FindTypeMapFor<Person, PersonDto>();
foreach (var propertyMap in map.GetPropertyMaps())
{
    var destProp = propertyMap.DestinationProperty.Name; // = "Id"
    var sourceMember = propertyMap.SourceMember.Name; // = "Id"
    var sourceMembers = propertyMap.SourceMembers; // Count = 1
}

但是当我遍历FullName属性映射时,我想实现propertyMap.SourceMembers导致两个SourceMembers FirstNameLastName

var map = AutoMapper.Mapper.Configuration.FindTypeMapFor<Person, PersonDto>();
foreach (var propertyMap in map.GetPropertyMaps())
{
    var destProp = propertyMap.DestinationProperty.Name; // = "FullName"
    var sourceMember = propertyMap.SourceMember.Name; // = "LastName" (I don't care)
    var sourceMembers = propertyMap.SourceMembers; // Count = 0 (want to achieve 2 for FirstName and LastName)
}

我的目标是基于初始化的自动映射器映射为orderBy功能创建一个自动化的相似映射。所以我需要知道(a)顺序和(b)sourceMembers。在上述情况下,我想从其源成员FullNameFirstName(按此顺序)获取LastName的映射。

是否可以正确地注册多个源成员,以便propertyMap.SourceMembers产生所有映射的源成员?如果是,映射初始化应该是什么样?

PS:我不想手工编写orderBy映射,因为借助自动映射器,我已经有了映射。

1 个答案:

答案 0 :(得分:0)

感谢Lucian Bargaoanu,我开发了以下 dirty 解决方法。

请注意,这是我第一次与解释表达式联系,所以请耐心接受我的解决方案的质量:

var map = AutoMapper.Mapper.Configuration.FindTypeMapFor<Person, PersonDto>();
foreach (var propertyMap in map.PropertyMaps)
{
    var destProp = propertyMap.DestinationMember.Name; // = "FullName"
    var sourceMember = propertyMap.SourceMember?.Name; // = "LastName" (I don't care)
    var sourceMembers = propertyMap.SourceMembers.ToList();
    if (sourceMembers.Count() == 0)
    {
        ResolveSourceMembersInOrder(sourceMembers,
            propertyMap.CustomMapExpression.Body as BinaryExpression);
    }

    // sourceMembers now yield the two desired sourceMembers "FirstName" and "LastName"
}

public static void ResolveSourceMembersInOrder(List<MemberInfo> memberInfos, BinaryExpression expression)
{
    if (memberInfos == null)
    {
        memberInfos = new List<MemberInfo>();
    }

    if (expression == null)
    {
        return;
    }

    var left = expression.Left;
    if (left.NodeType == ExpressionType.MemberAccess)
    {
        memberInfos.Add(MemberVisitor.GetMemberPath(left).FirstOrDefault());
    }
    else
    {
        ResolveSourceMembersInOrder(memberInfos, left as BinaryExpression);
    }

    var right = expression.Right;
    if (right.NodeType == ExpressionType.MemberAccess)
    {
        memberInfos.Add(MemberVisitor.GetMemberPath(right).FirstOrDefault());
    }
    else
    {
        ResolveSourceMembersInOrder(memberInfos, right as BinaryExpression);
    }
}