简体   繁体   English

Automapper-映射成员时如何获取包含类的类型?

[英]Automapper - How to get containing class type when mapping a member?

During a runtime mapping operation (like when you use ResolveUsing or a custom TypeConverter) is it possible to get the container classes (or types at least) of the source and destination members? 在运行时映射操作期间(例如当您使用ResolveUsing或自定义TypeConverter时),是否可以获取源成员和目标成员的容器类(至少是类型)?

I know that when you map one object to another, that the objects don't have to be members of some "parent" or "container" object, but I'm talking about the situation when AutoMapper is recursively copying a complex object. 我知道当您将一个对象映射到另一个对象时,这些对象不必是某个“父”或“容器”对象的成员,但是我在谈论的是AutoMapper递归复制复杂对象的情况。

Here's an example: 这是一个例子:

Here I'm copying (or setting it up at least) Cars & Boats of "kind A" to "kind B". 在这里,我将“ A类”的汽车和小船复制(或至少设置为“ B类”)。

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

Here is a solution using AutoMapper ResolutionContext Items as proposed by @Lucian Bargaoanu in comment. 这是@Lucian Bargaoanu在评论中提出的使用AutoMapper ResolutionContext项目的解决方案。 The idea is to use Before and After Map to store information in the Resolution Context. 想法是使用“前后映射”在“解析上下文”中存储信息。 I use a Stack to keep track of the whole chain of relationship. 我使用堆栈来跟踪整个关系链。

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

This will output: 这将输出:

I'm coming from CarA
I'm coming from boatA

Another way is to use custom value resolver: 另一种方法是使用自定义值解析器:

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

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

Then in you CustomResolver implementation: 然后在您的CustomResolver实现中:

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

And then: 接着:

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

See http://docs.automapper.org/en/stable/Custom-value-resolvers.html 参见http://docs.automapper.org/en/stable/Custom-value-resolvers.html

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM