Search code examples
c#.netdependency-injectionioc-containersimple-injector

Getting a singleton instance using SimpleInjector for a class which implements a generic type, not actually returning a singleton


I've been experiencing some strange code-issues, and finally seem to have noticed that what as supposed to be acting as Singleton, is not actually a singleton. This is a cache-class, so I am ending up having multiple-versions of the same cache. I've written some test-code as per below, and in my eyes this should work. Am I doing anything wrong, or have I stumbled upon a bug?

public class GenericClassesNotRegisteredAsSingletonTest
{
    public interface ICacheManager<T> { }

    public class SettingsData { }

    public class SettingsCache : CacheManager<SettingsData> { }

    public class CacheManager<T> : ICacheManager<T> { }

    [Test]
    public void Test()
    {
        var container = new Container();

        var registration = Lifestyle.Singleton
            .CreateRegistration(typeof(SettingsCache),
                typeof(SettingsCache), container);

        container.AddRegistration(
            typeof(ICacheManager<SettingsData>), registration);

        container.Verify();

        var cache1 = container.GetInstance<SettingsCache>();
        var cache2 = container.GetInstance<SettingsCache>();

        bool sameRef = cache1 == cache2;
        Assert.That(sameRef == true);
    }
}

Solution

  • You made the following registration:

    _container.AddRegistration(
        serviceType: typeof(ICacheManager<SettingsData>),
        registration: registration);
    

    And you're doing the following resolve:

    _container.GetInstance<SettingsCache>();
    

    You haven't registered SettingsCache explicitly, but only ICacheManager<SettingsData>. Since SettingsCache is a concrete class, Simple Injector will resolve it as transient instance for you.

    The solution is to either register SettingsCache explicitly or resolve ICacheManager<SettingsData> instead. You can make a second registration with using the same Registration instance. For instance:

    _container.AddRegistration(
        serviceType: typeof(SettingsCache),
        registration: registration);
    

    The Diagnostic Services will warn you about this this type of misconfiguration.