Search code examples
c#interfaceglobal-variablesinterface-implementationmultiple-interface-implem

Can I globally set the interface implementation to use?


I have an interface:

public interface IHHSDBUtils
{
    void SetupDB();

    bool TableExists(string tableName);
    . . .

...that has multiple implementers:

public class SQLiteHHSDBUtils : IHHSDBUtils
public class SQCEHHSDBUtils : IHHSDBUtils
public class FlatfileHHSDBUtils : IHHSDBUtils
public class TestHHSDBUtils : IHHSDBUtils

I want to be able to specify which implementer is going to be used from a globally accessible spot, such as:

public static class HHSConsts
{
    public static IHHSDBUtils hhsdbutil = SQLiteHHSDBUtils;

...and then call it like so from anywhere in the app:

private HHSDBUtils hhsdbutils { get; set; }
. . .
hhsdbutils = new HHSConsts.hhsdbutil;
hhsdbutils.SetupDB();

Is this possible? I get, "'SQLiteHHSDBUtils' is a 'type' but is used like a 'variable' with its assignment to hhsdbutil above.


Solution

  • You could do a poormans Factory implementation by creating an enum for each type and have a static factory method that creates the type for you. I stay as close to your current code snippets as possible.

    public enum HHSDBUtilsTypes 
    {
        Sqllite,
        SQCE,
        Flatfile,
        Test
    }
    
    public static class HHSConsts
    {
        private const string implementation = HHSDBUtilsTypes.Sqllite; // you might read this from the config file
    
        public static IHHSDBUtils GetUtils()
        {
             IHHSDBUtils impl;
             switch(implementation)
             {
                case HHSDBUtilsTypes.Sqllite:
                   impl = new SQLiteHHSDBUtils();
                break;
                case HHSDBUtilsTypes.SQCE:
                   impl = new SQCEHHSDBUtils();
                break;
                case HHSDBUtilsTypes.Sqllite:
                   impl = new FlatfileHHSDBUtils();
                break;
                default:
                   impl = new TestHHSDBUtils();
                break;
             }
             return impl;
        }
    }
    

    And you would use it like so:

    private IHHSDBUtils hhsdbutils { get; set; }
    //. . .
    hhsdbutils = HHSConsts.GetUtils();
    hhsdbutils.SetupDB();
    

    An other option is to use Activator.CreateInstance.

     const string fulltypename = "Your.Namespace.SQLiteHHSDBUtils"; // or read from config;
     hhsdbutils = (HHSDBUtils) Activator.CreateInstance(null, fulltypename).Unwrap();
    

    Make sure to test and measure performance, specially if you need to instantiate a lot of types often via any of these methods.

    If you want more control use a Dependency Injection/Inversion of Control framework like:

    Be aware though that all of these frameworks bring in their own powerfull features but also added complexity. If you feel you have to select a framework take maintainability and learnability as a dominant requirement.

    Here is some extra documentation on DI