简体   繁体   中英

Automapper - Value Resolver with generics problem

I am using Automapper with our asp net core application. For the mappings from type A -> B and A -> C , I need an external service to inject some additional data. Therefore I have written a ValueResolver<T> , where T is either B or C . As C# doesn't have OR operator for types, I use a generic T here.

For clarity, my value resolver looks like this:

public class MyValueResolver<T>: IValueResolver<A, T, string>
{
    private readonly IMyService _service;

    public MyValueResolver(IMyService service)
    {
        _service = service;
    }

    public string Resolve(A source, T destination, string destMember, ResolutionContext context)
    {
        // do something using only source and _service.
        return ...;
    }        
}

Now, in my startup I register automapper like this services.AddAutoMapper(); . Therefore, when I use it anywhere in my application, I just have to inject IMapper in the constructor and it will resolve MyValueResolver with IMyService dependency automatically.

The problem arises in tests when I don't use DI and I need both MyValueResolver<B> and MyValueResolver<C> . I tried the following:

        var mappingConfig = new MapperConfiguration(cfg => {
            cfg.AddProfile(new MappingProfile());
            cfg.ConstructServicesUsing(MyValueResolver =>
                new MyValueResolver<B>(service));
            cfg.ConstructServicesUsing(MyValueResolver =>
                new MyValueResolver<C>(service));
        });
        var mapper = new Mapper(mappingConfig);

But this doesn't work, as it sees tries to use the latter statement for both cases and fails with an error that it cannot cast MyValueResolver<C> to MyValueResolver<B> . But the method doesn't accept types with generics defined (I assume it is a C# limitation?) like this cfg.ConstructServicesUsing(MyValueResolver<C> => new MyValueResolver<C>(service));

Is there any workaround for this, or maybe a different pattern I could use?

I was using ConstructServicesUsing in a completely wrong way.

It takes a function , where Type - is a type of a ValueResolver I want to resolve and Object is the resolved instance. You should return null for the types you don't want to resolve.

So it looks along the lines:

cfg => cfg.ConstructServicesUsing(type => type == typeof(MyValueResolver<B>) ? new MyValueResolver<B>(service) : null));

Credit goes to @LucianBargaoanu for this answer.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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