Automapper - Как получить содержащий тип класса при отображении члена? - PullRequest
0 голосов
/ 26 июня 2018

Во время операции отображения во время выполнения (например, когда вы используете ResolveUsing или пользовательский TypeConverter) возможно ли получить классы контейнеров (или, по крайней мере, типы) членов источника и назначения?

Я знаю, что когда вы отображаете один объект на другой, объекты не обязательно должны быть членами какого-либо "родительского" или "контейнерного" объекта, но я говорю о ситуации, когда AutoMapper рекурсивно копирует комплекс объект.

Вот пример:

Здесь я копирую (или, по крайней мере, настраиваю) автомобили и лодки типа "А" в "вид Б".

public class VehicleCopyProfile : AutoMapper.Profile
{
    public VehicleCopyProfile()
    {
        this.CreateMap<CarA, CarB>();
        this.CreateMap<BoatA, BoatB>();

        this.CreateMap<WindshieldA, WindshieldB>(
            .ConvertUsing((s, d, resContext) =>
            {
                // *** How can I tell if s is coming from a Car or a Boat? ***
            });

    }
}

// Cars & Boats each have a Windshield

public class CarA
{
    public WindshieldA Windshield {get;set;}
}

public class BoatA
{
    public WindshieldA Windshield {get;set;}
}

public class WindshieldA
{
    public string Name {get;set;}
}





public class CarB
{
    public WindshieldB Windshield {get;set;}
}

public class BoatB
{
    public WindshieldB Windshield {get;set;}
}


public class WindshieldB
{
    public string Name {get;set;}
}

Ответы [ 2 ]

0 голосов
/ 04 июля 2018

Другой способ - использовать пользовательский преобразователь значений:

class CustomResolver<T1, T2>:IValueResolver ... { ... }

this.CreateMap<CarA, CarB>()
.ForMember(x => x.Windshield , opt => opt.ResolveUsing(new CustomResolver<CarA, CarB>()));

Тогда у вас CustomResolver реализация:

var windshieldB = Mapper.Map<WindshieldB>(windshieldA, x => {x.Items["type1"] = typeof(T1); x.Items["type2"] = typeof(T2);});

А потом:

this.CreateMap<WindshieldA, WindshieldB>(
            .ConvertUsing((s, d, resContext) =>
            {
                // resContext.Options.Items["type1"]
            });

См. http://docs.automapper.org/en/stable/Custom-value-resolvers.html

0 голосов
/ 29 июня 2018

Вот решение, использующее элементы AutoMapper ResolutionContext, предложенные @ Lucian Bargaoanu в комментарии. Идея состоит в том, чтобы использовать карту «До» и «После» для хранения информации в контексте разрешения. Я использую стек, чтобы отслеживать всю цепочку отношений.

namespace SO51101306
{
    public static class IMappingExpressionExtensions
    {
        public static IMappingExpression<A, B> RegisterChainOfTypes<A, B>(this IMappingExpression<A, B> mapping)
        {
            mapping.BeforeMap((a, b, ctx) => {
                ctx.PushTypeInChainOfTypes(typeof(A));
            });

            mapping.AfterMap((a, b, ctx) => {
                ctx.PopLastTypeInChainOfTypes();
            });
            return mapping;
        }
    }

    public static class ResolutionContextExtensions
    {
        const string chainOfTypesKey = "ChainOfTypes";

        private static Stack<Type> GetOrCreateChainOfTypesStack(ResolutionContext ctx)
        {
            var hasKey = ctx.Items.ContainsKey(chainOfTypesKey);
            return hasKey ? (Stack<Type>)ctx.Items[chainOfTypesKey] : new Stack<Type>();
        }

        public static void PushTypeInChainOfTypes(this ResolutionContext ctx, Type type)
        {
            var stack = GetOrCreateChainOfTypesStack(ctx);
            stack.Push(type);
            ctx.Items[chainOfTypesKey] = stack;
        }

        public static Type PopLastTypeInChainOfTypes(this ResolutionContext ctx)
        {
            var stack = (Stack<Type>)ctx.Items[chainOfTypesKey];
            return stack.Pop();
        }

        public static bool HasParentType(this ResolutionContext ctx, Type parentType)
        {
            var stack = GetOrCreateChainOfTypesStack(ctx);
            return stack.Contains(parentType);
        }

    }

    public class CarCopyProfile : Profile
    {
        public CarCopyProfile()
        {
            CreateMap<CarA, CarB>().RegisterChainOfTypes();
            CreateMap<BoatA, BoatB>().RegisterChainOfTypes();

            CreateMap<WindshieldA, WindshieldB>()
            .ConvertUsing((wa,wb,ctx)=> {
                if(ctx.HasParentType(typeof(CarA)))
                {
                    Console.WriteLine("I'm coming from CarA");
                    //Do specific stuff here
                }
                else if (ctx.HasParentType(typeof(BoatA)))
                {
                    Console.WriteLine("I'm coming from boatA");
                    //Do specific stuff here
                }
                return wb;
            });

        }
    }

    public class CarA
    {
        public WindshieldA Windshield { get; set; }
    }

    public class BoatA
    {
        public WindshieldA Windshield { get; set; }
    }

    public class CarB
    {
        public WindshieldB Windshield { get; set; }
    }

    public class BoatB
    {
        public WindshieldB Windshield { get; set; }
    }

    public class WindshieldA
    {
        public string Name { get; set; }
    }

    public class WindshieldB
    {
        public string Name { get; set; }
    }


    class Program
    {
        static void Main(string[] args)
        {
            Mapper.Initialize(c => c.AddProfile<CarCopyProfile>());

            var carA = new CarA{Windshield = new WindshieldA()};
            var boatA = new BoatA{Windshield = new WindshieldA()};

            var carB = Mapper.Map<CarB>(carA);
            var boatB = Mapper.Map<BoatB>(boatA);
        }
    }
}

Будет выведено:

I'm coming from CarA
I'm coming from boatA
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...