user3170354
user3170354

Reputation: 401

Resolving generic services in dotnet core

I am using an API which triggers the following method whenever data is accessible

public void Process(IData data)

IData is implemented by several data types (i.e. EventData and RegionData) which all will trigger this method whenever new data is available.

This incoming data should be mapped to my entities through IDataMapper:

IDataMapper<T,K> where T : IData where K : IEntity

My problem is how to resolve the corresponding DataMapper based on the type of the the incoming data. My current solution is to make a manual check:

switch(data.GetType().Name) {
   case nameof(EventData) :
      var mapper = scope.ServiceProvider.GetRequiredService<IDataMapper<EventData, EventEntity>>();
      break;

   case nameof(RegionData) :
      var mapper = scope.ServiceProvider.GetRequiredService<IDataMapper<RegionData, RegionEntity>>();
      break;

      .....

All data mappers are registered like this:

services.AddTransient<IDataMapper<EventData, EventEntity>, EventMapper>();
services.AddTransient<IDataMapper<RegionData, RegionEntity>, RegionMapper>();

Is it possible to make this more generic?

Upvotes: 1

Views: 62

Answers (1)

Silvermind
Silvermind

Reputation: 5944

You could make the mapper generic too and move the problem of type checking inside that class. That way you can 'just' register one mapper type. This is also how Microsofts ILogger<TCategory> works.

Example code:

using Microsoft.Extensions.DependencyInjection;

namespace ConsoleApp1
{
    class Program
    {
        static void Main(string[] args)
        {
            var serviceCollection = new ServiceCollection();
            serviceCollection.AddTransient(typeof(IDataMapper<,>), typeof(DataMapper<,>));
            serviceCollection.AddTransient<EventService>();
            serviceCollection.AddTransient<RegionService>();
            var provider = serviceCollection.BuildServiceProvider();
            var eventService = provider.GetRequiredService<EventService>();
            var regionService = provider.GetRequiredService<RegionService>();
        }
    }

    class EventService
    {
        public EventService(IDataMapper<EventData, EventEntity> mapper)
        {
            mapper.Map(new EventData(), new EventEntity());
        }
    }

    class RegionService
    {
        public RegionService(IDataMapper<RegionData, RegionEntity> mapper)
        {
            mapper.Map(new RegionData(), new RegionEntity());
        }
    }

    public interface IData { }

    public interface IEntity { }

    public interface IDataMapper<T, K> where T : IData where K : IEntity
    {
        void Map(T data, K entity);
    }

    public class EventData : IData { }

    public class RegionData : IData { }

    public class EventEntity : IEntity { }

    public class RegionEntity : IEntity { }

    public class DataMapper<T, K> : IDataMapper<T, K> where T : IData where K : IEntity
    {
        public void Map(T data, K entity)
        {
            if (data is EventData eData && entity is EventEntity eEntity)
            {
                // map event
            }
            else if (data is RegionData rData && entity is RegionEntity rEntity)
            {
                // map region
            }
        }
    }
}

Upvotes: 1

Related Questions