3

the title is, maybe, misleading but basically I want the DryIoc.Container to resolve a specific implementation of an interface whose type (the type of the class the implements the interface) is given at runtime ( multiple implementations of the same interface are registered ). I can't use serviceKey to identify implementations because the code that resolves the implementation is expected to do something like : container.Resolve<IService>(*** here specify the runtime type of the implementation ***) to get the implementation we want (the type of the implementation is acquired via a configuration we read at runtime).

    using System;
    using DryIoc;
    namespace DryIoc_example
    {
        interface IService { }
        class ServiceImpl_1 : IService { }
        class ServiceImpl_2 : IService { }

        class Program
        {
            static void Main(string[] args)
            {
                var container = new Container();
                // register my implementations of IService
                // this could be done at runtime using
                // container.Register(typeof(IService), typeof(ServiceImpl_1));
                container.Register<IService, ServiceImpl_1>();
                container.Register<IService, ServiceImpl_2>();

                // now, i want the container to resolve a specific
                // implementation of IService ( ServiceImpl_2 in this case)

                // this line doesn't work and throws
                var myService = container.Resolve<IService>(typeof(ServiceImpl_2));

                // this line is expected to print the type of ServiceImpl_2
                Console.WriteLine(myService.GetType());
            }
        }
    }

`

the code above throws :

Unable to resolve DryIoc_example.IService {RequiredServiceType=DryIoc_example.ServiceImpl_2}

Where CurrentScope: null

  and ResolutionScope: null

  and Found registrations:

  DefaultKey.Of(0),{ID=20, ImplType=DryIoc_example.ServiceImpl_1}}

  DefaultKey.Of(1),{ID=21, ImplType=DryIoc_example.ServiceImpl_2}}

I know I can get all the registered implementations for an interface and filtering the one that has the implementation I want (using code similar to this response https://stackoverflow.com/a/37069854/5767019 by the maintainer of DryIoc ), but I couldn't figure out a way to make the container resolve it when I ask it to !

Abdelghani
  • 73
  • 8

1 Answers1

2

The answer for DryIoc, Spring.Net's GetObjectsOfType equivalent? is pretty much on the spot.

Repeating the options here:

Using implementation type as service key

container.Register<IService, ServiceImpl_1>(serviceKey: typeof(ServiceImpl_1));
container.Resolve<IService>(serviceKey: typeof(ServiceImpl_1));

Using RegisterMany

This will do registration with all implemented public types as service types, including implementation type itself:

using System;
using DryIoc;
namespace DryIoc_example
{
    interface IService {}
    class ServiceImpl_1 : IService {}
    class ServiceImpl_2 : IService {}

    public class Program
    {
        public static void Main()
        {
            var container = new Container();
            
            container.RegisterMany<ServiceImpl_1>(nonPublicServiceTypes: true);
            container.RegisterMany<ServiceImpl_2>(nonPublicServiceTypes: true);
            
            var myService = container.Resolve<IService>(typeof(ServiceImpl_2));
            
            // this line is expected to print the type of ServiceImpl_2
            Console.WriteLine(myService.GetType());
        }
    }
}

Live example

Select from container registrations manually

Find the registered factory with given implementation type, and get the actual default key used for registration. Resolve using the key:

using System;
using System.Linq;
using DryIoc;

namespace DryIoc_example
{
    public interface IService {}
    class ServiceImpl_1 : IService {}
    class ServiceImpl_2 : IService {}

    public class Program
    {
        public static void Main()
        {
                var container = new Container();

                container.Register<IService, ServiceImpl_1>();
                container.Register<IService, ServiceImpl_2>();
            
                var myService = container.TryResolveByImplementation<IService>(typeof(ServiceImpl_1));
                

                // this line is expected to print the type of ServiceImpl_1
                Console.WriteLine(myService.GetType());
        }
    }
    
    public static class ContainerExtensions
    {
        public static TService TryResolveByImplementation<TService>(this IContainer container, Type implementationType)
        {
            var factory = container.GetAllServiceFactories(typeof(TService))
                .FirstOrDefault(f => f.Value.ImplementationType == implementationType);
            
            return factory != null 
                ? container.Resolve<TService>(serviceKey: factory.Key) 
                : default(TService);
        }
    }
}

Live example

dadhi
  • 4,807
  • 19
  • 25
  • Thank you sir, your third option did it for me, now All my unit tests are GREEN :) I've been banging my head against a wall for most of the night then gave up on it and posted this question and within a couple of hours I got my response :) thanks again sir ! – Abdelghani Aug 17 '16 at 08:04
  • 1
    The code comment wrongly mentions it would return the type of ServiceImpl_2, but it returns the type of ServiceImpl_1. – Mitja Aug 17 '23 at 05:45
  • @mitja fixed, thanks – dadhi Aug 25 '23 at 09:11