15

We need to use an unmanaged library in our code that has static methods. I'd like to introduce the library operation as a dependency in my code. And apart from having static methods, the library has an initialization method and a settings method, both are global. So I can't just wrap this in an instance class, because if one instance changes a setting, all other instances will be affected, and if one instance gets initialized, all other instances will be reinitialized.

I thought about introducing it as a singleton class. This way it will be in an instance class, but there will only be one instance thus I won't have to worry about changing the settings or initialization. What do you think about this approach? I'm pretty new to the dependency injection pattern and I'm not sure if the singleton pattern is a good solution? What would your solution be to a similar case?

Edit: The initialization takes a parameter too, so I can't just lock the method calls and re-initialize and change settings every time it is called.

Edit 2: Here are the signatures of some methods:

public static void Initialize(int someParameter)
// Parameter can only be changed by re-initalization which
// will reset all the settings back to their default values.

public static float[] Method1(int someNumber, float[] someArray)

public static void ChangeSetting(string settingName, int settingValue)
hattenn
  • 4,371
  • 9
  • 41
  • 80
  • The class you are trying to wrap is it static or only some static methods? Does your wrapper need to provide any extra functionality? – JMan Feb 15 '13 at 12:46
  • Your idea seems sensible – sll Feb 15 '13 at 12:47
  • @Jeroen it needs to provide overloads to some methods. All the methods in the library take arrays, and I'd like to wrap them in classes. The library is written in C++ and the class I'm trying to wrap is static, not just the functions. – hattenn Feb 15 '13 at 12:50
  • Do you need to ever set the settings more than once? Or could that be done one time when the app starts? – Steven Doggart Feb 15 '13 at 12:51
  • @StevenDoggart I definitely need to set the settings more than once. – hattenn Feb 15 '13 at 12:55
  • There isn't much that can't be wrapped at some level - could you post the signatures of some of the methods of this class, particularly the initialisation method? – levelnis Feb 15 '13 at 13:16
  • @levelnis Just did it. – hattenn Feb 15 '13 at 13:21
  • Return types? void I assume... – levelnis Feb 15 '13 at 13:24
  • If it's a static class (class that contains all static members), you've already found a solution: have it as singleton. You cannot have 2 different behaviors of the static class, since static is a singleton by nature anyway. – Tengiz Feb 15 '13 at 13:25
  • @levelnis Sorry just added them. – hattenn Feb 15 '13 at 13:25
  • Seeing your edits, I definitely agree with you that introducing a singleton class is a good solution. – A. Rodas Feb 15 '13 at 13:29

2 Answers2

10

If you only need to set the settings once at start up, then I would recommend making a non-static wrapper class which does all the initialization of the static class in its own static constructor. That way you can be assured that it will only happen once:

public class MyWrapper
{
    public MyWrapper()
    {
        // Do any necessary instance initialization here
    }

    static MyWrapper()
    {
        UnManagedStaticClass.Initialize();
        UnManagedStaticClass.Settings = ...;
    }

    public void Method1()
    {
        UnManagedStaticClass.Method1();
    }
}

However, if you need to change the settings each time you call it, and you want to make your instances thread-safe, then I would recommend locking on a static object so that you don't accidentally overwrite the static settings while they're still in use by another thread:

public class MyWrapper
{
    public MyWrapper()
    {
        // Do any necessary instance initialization here
    }

    static MyWrapper()
    {
        UnManagedStaticClass.Initialize();
    }

    static object lockRoot = new Object();

    public void Method1()
    {
        lock (lockRoot)
        {
            UnManagedStaticClass.Settings = ...;
            UnManagedStaticClass.Method1();
        }
    }
}   

If you need to pass initialization parameters into your class's instance constructor, then you could do that too by having a static flag field:

public class MyWrapper
{
    public MyWrapper(InitParameters p)
    {
        lock (lockRoot)
        {
            if (!initialized)
            {
                UnManagedStaticClass.Initialize(p);
                initialized = true;
            }
        }
    }

    static bool initialized = false;
    static object lockRoot = new Object();

    public void Method1()
    {
        lock (lockRoot)
        {
            UnManagedStaticClass.Settings = ...;
            UnManagedStaticClass.Method1();
        }
    }
}

If you also need to re-initialize each time, but you are concerned about performance because re-initializing is too slow, then the only other option (outside of the dreaded singleton) is to auto-detect if you need to re-initialize and only do it when necessary. At least then, the only time it will happen is when two threads are using two different instances at the same time. You could do it like this:

public class MyWrapper
{
    public MyWrapper(InitParameters initParameters, Settings settings)
    {
        this.initParameters = initParameters;
        this.settings = settings;
    }

    private InitParameters initParameters;
    private Settings settings;
    static MyWrapper currentOwnerInstance;
    static object lockRoot = new Object();

    private void InitializeIfNecessary()
    {
        if (currentOwnerInstance != this)
        {
            currentOwnerInstance = this;
            UnManagedStaticClass.Initialize(initParameters);
            UnManagedStaticClass.Settings = settings;
        }
    }

    public void Method1()
    {
        lock (lockRoot)
        {
            InitializeIfNecessary();
            UnManagedStaticClass.Method1();
        }
    }
}
Steven Doggart
  • 43,358
  • 8
  • 68
  • 105
  • It's not just about thread-safety. This way if one instance changes settings, all the other instances will be affected too. – hattenn Feb 15 '13 at 13:10
  • No, other instances will not be affected so long as you always set the settings first (inside the lock block). – Steven Doggart Feb 15 '13 at 13:12
  • And initialization takes a parameter too, with this method, every time I call it it should be re-initialized and its settings should be reset, which is likely to slow down all these operations drastically. An mind you, this library will be used extensively. – hattenn Feb 15 '13 at 13:12
  • If you want a more detailed answer, you'll need to provide a more detailed question. – Steven Doggart Feb 15 '13 at 13:13
  • I don't want a more detailed answer, no need to take it personally. I'm just clearing up the situation, explaining why your solution wouldn't work. Thanks for your time though. – hattenn Feb 15 '13 at 13:14
  • I didn't mean to imply I was upset. I apologize that I gave you that impression. – Steven Doggart Feb 15 '13 at 13:16
  • no problem - sorry for the misunderstanding. I appreciate your input. – hattenn Feb 15 '13 at 13:16
  • But the problem is, if two instances should be initialized differently, they are not compatible. I have to re-initialize before every method call, and then set the settings again (unless their settings and initializations were exactly the same). – hattenn Feb 15 '13 at 13:23
  • I mean it's not just the problem of determining if the class was initialized or not, it's also important what parameter the class was initialized with. And that parameter can only be re-set with a re-initialization. – hattenn Feb 15 '13 at 13:24
  • Well, if that's the case, and re-initializing is too time consuming, then I guess a singleton is your only option. I suppose you could use an instance-specific guid to see if the settings are currently set to your own instance's settings, and only reinitialize if they are set to some other instance's settings, but that is getting a little nuts. – Steven Doggart Feb 15 '13 at 13:27
  • I don't have much experience with these situations but, in your examples you always lock `Method1`. Won't it cause it to only be called once at a time? Will two different threads be able to call it at the same time? – hattenn Feb 15 '13 at 13:59
  • Both will certainly be able to call it at the same time, safely, but they will process serially. The second thread to call it will hang waiting until the first thread's call to it is complete. Since all of the instances are sharing an underlying global resource, that's how I'd think you'd want it to work, unless, as you implied, all the instances will share the same settings anyway. – Steven Doggart Feb 15 '13 at 14:02
  • That's what I meant, they will have to wait till the other thread finishes it's call. Which pretty much means you can't parallelize it. At least with the singleton solution, I can parallelize it. Which is not a requirement at the moment, but looking at the pros / cons, it sounds more likely that I'd need parallelization than different instances with different settings. The perfect solution would be to have both of it, parallelizable and capable of having different settings for different instances. – hattenn Feb 15 '13 at 14:07
  • I'd say you don't need the singleton. If you use a singleton, you'll be unnecessarily painting yourself into a corner where you won't be able to support different instances with different settings down the road. If you don't need them to have separate settings, just make it a typical instance class where each instance takes the settings, but then only have the first instance actually use the settings to initialize the underlying static class (using a `static bool initialized`). – Steven Doggart Feb 15 '13 at 14:13
  • That way, you get the best of both worlds. It will be injectable, thread-safe, and it's public interface will support different settings for each instance in case some day you actually need it to work that way. – Steven Doggart Feb 15 '13 at 14:14
1

I would use a stateless service class, and pass in state info for the static class with each method call. Without knowing any details of you class, I'll just show another example of this with a c# static class.

public static class LegacyCode
{
    public static void Initialize(int p1, string p2)
    {
        //some static state
    }
    public static void ChangeSettings(bool p3, double p4)
    {
        //some static state
    }
    public static void DoSomething(string someOtherParam)
    {
        //execute based on some static state
    }
}

public class LegacyCodeFacadeService
{
    public void PerformLegacyCodeActivity(LegacyCodeState state, LegacyCodeParams legacyParams)
    {
        lock (_lockObject)
        {
            LegacyCode.Initialize(state.P1, state.P2);
            LegacyCode.ChangeSettings(state.P3, state.P4);
            LegacyCode.DoSomething(legacyParams.SomeOtherParam);
            //do something to reset state, perhaps
        }
    }
}

You'll have to fill in the blanks a little bit, but hopefully you get the idea. The point is to set state on the static object for the minimum amount of time needed, and lock access to it that entire time, so no other callers can be affected by your global state change. You must create new instances of this class to use it, so it is fully injectable and testable (except the step of extracting an interface, which I skipped for brevity).

There are a lot of options in implementation here. For example, if you have to change LegacyCodeState a lot, but only to a small number of specific states, you could have overloads that do the work of managing those states.

EDIT

This is preferable to a singleton in a lot of ways, most importantly that you won't be able to accumulate and couple to global state: this turns global state in to non-global state if it is the only entry point to your static class. However, in case you do end up needing a singleton, you can make it easy to switch by encapsulating the constructor here.

public class LegacyCodeFacadeService
{
    private LegacyCodeFacadeService() { }

    public static LegacyCodeFacadeService GetInstance()
    {
        //now we can change lifestyle management strategies later, if needed
        return new LegacyCodeFacadeService();
    }

    public void PerformLegacyCodeActivity(LegacyCodeState state, LegacyCodeParams legacyParams)
    {
        lock (_lockObject)
        {
            LegacyCode.Initialize(state.P1, state.P2);
            LegacyCode.ChangeSettings(state.P3, state.P4);
            LegacyCode.DoSomething(legacyParams.SomeOtherParam);
            //do something to reset state, perhaps
        }
    }
}
tallseth
  • 3,635
  • 1
  • 23
  • 24
  • I wouldn't like to re-initialize the object often, and also this way it will be (as far as I can understand) impossible to parallelize in case it's needed. Thanks for the input though. – hattenn Feb 15 '13 at 13:38
  • If you use a singleton, you definitely won't be able to *parallelize* in the future. Resetting the settings as needed is the only way to solve *that* issue. – Steven Doggart Feb 15 '13 at 13:41
  • You can't parallelize actions that need to happen in with different global state set anyway. Is initialization expensive? If not, no need to care. If so, only init when some init param changes. – tallseth Feb 15 '13 at 13:42
  • @StevenDoggart I don't understand why I won't be able to parallelize if it's singleton. I can have many calls to a method at the same time (other than the initialization and settings methods). If it is locked this way, it will always have to wait till the end of the operation. – hattenn Feb 15 '13 at 13:44
  • You can't if each thread needs different settings, which I thought was what you were concerned about. – Steven Doggart Feb 15 '13 at 13:48
  • Yeah I know, but if they don't need different settings then I can. As I've said in the question, my biggest problem is not having different instances of the library, I just want to be able to wrap it in an instance class so I can just extract an interface out of it and use it with dependency injection pattern. This way suggested by tallseth, even if I have one object, the method will be locked every time and I definitely won't be able to make more than one call at a time. – hattenn Feb 15 '13 at 13:50
  • Well, it would seem, then, that if you don't care about having different settings for different instances, then you just need to pass them in and only set them if it hasn't already been done yet (using a static bool flag, as demonstrated in my example). – Steven Doggart Feb 15 '13 at 13:55