Search code examples
dryioc

Open Generics Registration


Suppose I have the following classes:

public class Setup { }

public class Configuration<T> where T : class
{
    internal Configuration(Setup setup) { }
}

public class Process<T> where T : class
{
    internal Process(Configuration<T> configuration) { }
}

I want to register these classes in DryIoc and need each Process<T> to be singleton (as would be Configuration<T>). So, Process<ClassA> would resolve the same instance, and Process<ClassB> will do the same. But Process<ClassA> and Process<ClassB> would be 2 different instances.
The same applies to Configuration<T>.
How would I register these 3 classes to achieve what I need?
Note that constructors are internal.
This is what I've done without success:

var container = new Container();
container.Register<Setup>(Reuse.Singleton);
container.Register(typeof (Configuration<>), 
    made: Made.Of(typeof (Configuration<>).GetConstructorOrNull(true, typeof (Setup))));
container.Register(typeof(Process<>), Reuse.Singleton,
    Made.Of(typeof(Process<>).GetConstructorOrNull(true, typeof(Configuration<>))));

I get: "An exception of type 'System.NullReferenceException' occurred in DryIoc.dll but was not handled in user code" when, as an example I do
var a = container.Resolve<Process<EventArgs>>();


Solution

  • The problem is with getting constructor from generic type. For now you may use DryIoc API to get ConstructorWithResolvableArgumentsIncludingNonPublic:

    Working sample looks like that:

    var container = new Container();
    
    container.Register<Setup>(Reuse.Singleton);
    
    container.Register(typeof(Configuration<>), Reuse.Singleton,
        made: FactoryMethod.ConstructorWithResolvableArgumentsIncludingNonPublic);
    
    container.Register(typeof(Process<>), Reuse.Singleton,
        FactoryMethod.ConstructorWithResolvableArgumentsIncludingNonPublic);
    
    var p = container.Resolve<Process<EventArgs>>();
    

    In future versions it will be more simple like FactoryMethod.Constructor(includeNonPublic: true).

    Update with workaround:

    This is an actual issue in DryIoc 2.9.7 with creating singletons with internal constructor. The fix is on the way. For now you can use a workaround by disabling certain singleton optimizations with rule:

    var container = new Container(rules => rules.WithoutEagerCachingSingletonForFasterAccess());
    

    Updated live sample.

    Update with fix:

    The problem is fixed in DryIoc 2.10