16

I am trying to rewrite some code in .Net Core using the built in .Net Dependency Injection. Previously, I was using the current code to create the instance (It was using Unity for DI) which worked great.

var instance = (IPipe)UnityHelper.Container.Resolve(implementation);

For .Net Core I firstly tried the standard Activator.CreateInstance and this worked fine and created the instance of IPipe I was expecting.

var instance = (IPipe)Activator.CreateInstance(implementation)

However. The issue then, is if the implementations are injecting services in the ctor then they won't be resolved (Which is why I was using the Unity.Resolve in the previous project to get around this).

After some research, I found out about the ActivatorUtilities class and I've swapped this out for the code below (serviceProvider is IServiceProvider)

var instance = ActivatorUtilities.CreateInstance<IPipe>(serviceProvider, implementation);

However, I am now getting the current error.

A suitable constructor for type 'IPipe' could not be located. Ensure the type is concrete and services are registered for all parameters of a public constructor.

I don't understand why Activator.CreateInstance works fine but this is complaining about the IPipe constructor?

Kirk Larkin
  • 84,915
  • 16
  • 214
  • 203
YodasMyDad
  • 9,248
  • 24
  • 76
  • 121

1 Answers1

37

The generic ActivatorUtilities.CreateInstance<T>(IServiceProvider, Object[]) will actually create an instance of type T and attempt to resolve the type’s constructor arguments using the service provider. The object array you can pass is for additional constructor arguments that are not provided by the service provider.

If you just want to create an instance of a runtime type and have the DI container inject the dependencies, then you will need to use the non-generic ActivatorUtilities.CreateInstance(IServiceProvider, Type, Object[]).

That method returns an object, so you have to type-cast it, if you want to use it. For example:

var instance = (IPipe)ActivatorUtilities.CreateInstance(serviceProvider, pipeType);
poke
  • 369,085
  • 72
  • 557
  • 602
  • 1
    The generic and non-generic versions of CreateInstance are identical. The non-generic version calls the generic version. Which one you use is just up to which syntax you prefer. – Julius Aug 05 '20 at 09:30
  • 4
    @Julius it’s the other way around, the generic calls the non-generic, but yeah, they both do the same. My point was that with the _generic_ version (which OP was using), the argument is not the implementation that should be created but constructor arguments. Since OP wanted to create the implementation type dynamically, they had to use the non-generic version. Because if you have a runtime type reference, you cannot use the generic method without reflection. – poke Aug 05 '20 at 11:50
  • Yes you are right. Good update - I wasn't exactly sure what difference you were making between them. – Julius Aug 06 '20 at 12:07
  • Is there a way to combine both DI type resolution and parametrized instance activation? If not, I think that might be a useful feature: https://stackoverflow.com/q/69207420/1768303 – noseratio Sep 16 '21 at 11:21