3

Just yestarday I posted this:

Automapper - Inheritance mapper not working with type converter

Now I'm trying to do what @jimmy-bogard said in his answer, but unfortunately still with no success. Base members don't get mapped.

Jimmy said:

However, you CAN use ConstructUsing to build out the initial destination object. Or a custom AfterMap, that's also inherited. Just not ConvertUsing.

Here is my new code.

/* BaseClassConstructor.cs */
public class BaseClassConstructor {
    public static BaseClass Construct(ResolutionContext context) {
        if (context == null || context.IsSourceValueNull)
            return null;

        var src = (SourceClass)context.SourceValue;

        return new BaseClass() {
            CommonAttr = src.SourceAttr
        };
    }
}

/* AutoMapperConfig.cs */
public static class AutoMapperConfig {

    public static void RegisterMappings() {
        AutoMapper.Mapper.Initialize(config => {
        config
            .CreateMap<SourceClass, BaseClass>()
            .Include<SourceClass, DerivedClass1>()
            .Include<SourceClass, DerivedClass2>()
            .ConstructUsing(s => BaseClassConstructor.Construct(s));

        config
            .CreateMap<SourceClass, DerivedClass1>()
            .ForMember(dest => dest.Dummy, o => o.MapFrom(src => src.SourceAttr2))
            .IncludeBase<SourceClass, BaseClass>();
        });
    }
}

Did I miss something? Am I using ConstructUsing the right way?

Any help would be appreciated.

Community
  • 1
  • 1
gabaros
  • 743
  • 1
  • 6
  • 24
  • What do you want to achieve? Making Mapper.Map(source) work? – Evk May 26 '16 at 20:14
  • Yes! @Evk. With all base attributes correctly mapped. – gabaros May 26 '16 at 20:24
  • And you need to use type converter? Because in your example you really do not need it. – Evk May 26 '16 at 20:29
  • Yes! @Evk, my example is very basic, just for demo purposes. Actually my mappings are more complicated than that. eg. I need for some attributes to find out a value in a DB and map them accordingly. – gabaros May 26 '16 at 20:34

1 Answers1

2

The way you do it now it won't work, because in ConstructUsing you create an instance of BaseClass, while when you map source to Derived1 class - you need an instance of Derived1 class, and BaseClass cannot be converted to that (downcast). However you can do it like this:

public class BaseClassConstructor {
    public static T Construct<T>(ResolutionContext context) where T : BaseClass, new() {
        if (context == null || context.IsSourceValueNull)
            return null;

        var src = (SourceClass) context.SourceValue;

        return new T() {
            CommonAttr = src.SourceAttr
        };
    }
}

/* AutoMapperConfig.cs */
public static class AutoMapperConfig
{

    public static void RegisterMappings()
    {
        AutoMapper.Mapper.Initialize(config => {
            config
                .CreateMap<SourceClass, BaseClass>();

            config
                .CreateMap<SourceClass, DerivedClass1>()
                .ForMember(dest => dest.Dummy, o => o.MapFrom(src => src.SourceAttr2))
                .IncludeBase<SourceClass, BaseClass>()
                .ConstructUsing((s, ctx) => BaseClassConstructor.Construct<DerivedClass1>(ctx));

            config
                .CreateMap<SourceClass, DerivedClass2>()
                .ForMember(dest => dest.Dummy, o => o.MapFrom(src => src.SourceAttr2))
                .IncludeBase<SourceClass, BaseClass>()
                .ConstructUsing((s, ctx) => BaseClassConstructor.Construct<DerivedClass2>(ctx));
        });
    }
}

Basically I changed your Construct method to return instances of derived classes too, and then use ConstructUsing, but not on base class mapping but on Derived classes mappings.

Evk
  • 98,527
  • 8
  • 141
  • 191
  • Thanks! You've helped me a lot. However I don't see the need to inheritance mappings. I just removed the base mapping, and leave the derived ones without the IncludeBase call, and every thing work fine, because the base mapping really happens in derived mappings. – gabaros May 26 '16 at 21:10
  • Yes, I just left that in case in real situation you partially map base class properties using ForMember and only map complex ones using Construct. Otherwise you dont need all this. – Evk May 26 '16 at 21:12