Singleton with Dependency Injection
Asked Answered
E

1

5

I decided to use singleton in order to load some file when the application started and use this configuration throughout the app lifetime as this file is changed once in a year. There is a singleton:

 public class Singleton
 {
    private static IReader reader;

    private Singleton(IReader reader)
    {
        Singleton.reader = reader;
    }

    private static readonly Lazy<Dictionary<string, HashSet<string>>> lazy =
    new Lazy<Dictionary<string, HashSet<string>>>(() => reader.ReadData("config") );


    public static Dictionary<string, HashSet<string>> Instance { get { return lazy.Value; } }
}

And on Appstart I have:

 IWindsorContainer container = new WindsorContainer();
 container.Install(FromAssembly.This());

And on WindsorInstaller I have:

public class WindsorInstaller : IWindsorInstaller
{
    public void Install(IWindsorContainer container, IConfigurationStore store)
    {
        container.Register(Component.For<IReader>().ImplementedBy<MyReader>());
    }
}

My reader class is following:

 public class MyReader : IReader
 {
    public Dictionary<string, HashSet<string>> ReadData(string source)
    {
        /*some code*/
        return dict;
    }
 }

It seems that there is no injection happening on Singleton and reader is null and I get error: Object reference not set to an instance of an object. Can you please suggest what I am doing wrong and how to do it better (probably not use singleton at all)?

Etruria answered 8/5, 2018 at 0:24 Comment(3)
I don't see any class named MyReader. Is something missing from your example?Wolfgang
Does that DI work with private constructors? If it were my code, the constructor would be protected static.Heterosexual
The DI container looks for public constructor of class when initializing dependency. Singleton does not have public constructor. That's why reader is not being injected from the container. In your singleton code the private constructor is nowhere being used so even if you initialize reader manually in constructor, reader will be null.Borer
A
8

Your concept of the singleton with dependency injection is a bit skewed if the intention is to use it with a container yet still use statics.

Plus your class has a private constructor. How is the container suppose to explicitly inject dependencies into a private constructor?

Construct the interface/abstraction of the intended singleton.

public interface ISingleton {
    Dictionary<string, HashSet<string>> Instance { get; }
}

and implementation...

public class Singleton: ISingleton {
    private readonly Lazy<Dictionary<string, HashSet<string>>> lazy;

    public Singleton(IReader reader) {
        this.lazy = new Lazy<Dictionary<string, HashSet<string>>>(() => reader.ReadData("config") );
    }

    public Dictionary<string, HashSet<string>> Instance { get { return lazy.Value; } }
}

You then register it with the container as a singleton

public class WindsorInstaller : IWindsorInstaller {
    public void Install(IWindsorContainer container, IConfigurationStore store) {
        container.Register(Component.For<IReader>().ImplementedBy<MyReader>());
        container.Register(Component.For<ISingleton>().ImplementedBy<Singleton>().LifestyleSingleton());
    }
}

Any class that has ISingeton as a dependency will get the same instance injected when requested and the Singleton implementation will get its dependency when being resolved.

Aventurine answered 8/5, 2018 at 1:18 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.