Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C# Static constructors design problem - need to specify parameter

I have a re-occurring design problem with certain classes which require one-off initialization with a parameter such as the name of an external resource such as a config file.

For example, I have a corelib project which provides application-wide logging, configuration and general helper methods. This object could use a static constructor to initialize itself but it need access to a config file which it can't find itself.

I can see a couple of solutions, but both of these don't seem quite right:

1) Use a constructor with a parameter. But then each object which requires corelib functionality should also know the name of the config file, so this has to be passed around the application. Also if I implemented corelib as a singleton I would also have to pass the config file as a parameter to the GetInstance method, which I believe is also not right.

2) Create a static property or method to pass through the config file or other external parameter.

I have sort of used the latter method and created a Load method which initializes an inner class which it passes through the config file in the constructor. Then this inner class is exposed through a public property MyCoreLib.

public static class CoreLib
{
    private static MyCoreLib myCoreLib;

    public static void Load(string configFile)
    {
        myCoreLib = new MyCoreLib(configFile);
    }

    public static MyCoreLib MyCoreLib
    {
        get { return myCoreLib; }
    }

    public class MyCoreLib
    {
        private string configFile;

        public MyCoreLib(string configFile)
        {
            this.configFile = configFile;
        }

        public void DoSomething()
        {
        }
    }
}

I'm still not happy though. The inner class is not initialized until you call the load method, so that needs to be considered anywhere the MyCoreLib is accessed. Also there is nothing to stop someone calling the load method again.

Any other patterns or ideas how to accomplish this?

like image 441
Neil Dobson Avatar asked Aug 27 '26 07:08

Neil Dobson


2 Answers

You need a common location to store this. You could use the app.config even if this is a seperate assembly by defining a config section in the library assembly and referencing it you proceess app.config. Or you could just add a generic setting to appSettings and reference that without using strongly typed settings. If the value is user entered then you could use isolated storage. Finally you could put it in a well known location in the registry at install time.

For code the following is encapsulted better

    public interface ICoreLib
    {
        void SomeMethod();
    }
    public static class CoreLibManager
    {
        private static ICoreLib coreLib;
        private static volatile bool initialized;
        private static readonly object lockObject = new object();
        public static ICoreLib CoreLib
        {
            get
            {
                Inititialize();
                return coreLib;
            }
        }

        /// <summary>
        /// The inititialize.
        /// </summary>
        private static void Inititialize()
        {
            if (initialized)
            {
                lock (lockObject)
                {
                    if (!initialized)
                    {
                        string configFile =  // Fech from common location
                        coreLib = new MyCoreLib(configFile);
                        initialized = true;
                    }
                }
            }
        }

        /// <summary>
        /// The my core lib.
        /// </summary>
        private class MyCoreLib : ICoreLib
        {
            public MyCoreLib(string configPath)
            {
            }
            public void SomeMethod()
            {
            }
        }
    }
like image 60
csaam Avatar answered Aug 29 '26 22:08

csaam


When you have global state like this that you need to initialize and it requires outside input to complete initialization (such as a config file), then you're stuck with the outside code that knows about the input having to call Load or Initialize to initialize your global state. There's no way around this.

The issue that you've correctly observed, however, is that anybody could try to use the global state before it has been properly Initialized, which is the downside to having it exposed in this way. The way you get around this is by refactoring all of the stateful parts of your global library into an instance class and passing references to that instance through your application. Because you control when it is created and initialized, you can now ensure it has valid state before you pass it along. You trade off the convenience of global state for the better insulation you're after.

like image 24
Dan Bryant Avatar answered Aug 29 '26 21:08

Dan Bryant



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!