1

There's a scenario I have where, in the main entry point of my C# program, I iterate a directory of managed DLLs, load each of them, and pass a factory object to each of them to get a mapping of implementations for various public interfaces. After the iteration is completed, I have one big map of interfaces and their corresponding implementations.

This factory object is needed by many unrelated objects in the system. There's also state that goes with the factory that identifies if specific DLLs were found, because knowing if I have a certain implementation sometimes influences the UI (disabling elements in the UI when they are not present).

What is the best way to share this factory + the accompanying informational state? I can either store it as a global, or I can pass it through hundreds of functions in my code, but I like neither of these solutions.

Challenges like this make it really hard to avoid the Singleton pattern. I can't be creating these factories on-demand all over the place because I would be repeating the same, heavy work each time and that's unnecessary.

What are some alternative solutions that don't involve abusing global variables (which is error prone), polluting interfaces, or impacting performance? Note that if the singleton pattern (as a class) is justified here and there are no reasonable alternatives, I can accept that as an answer.

As far as research goes, I did find answers like this one that mention dependency injection, however I'm not sure how that would apply here. I've also considered some sort of observer pattern for this, but again I don't see how I could use that mechanism to avoid the problems here. It feels like no matter what, when you boil each idea down to the essentials, it comes down to either global state or polluting interfaces.

void.pointer
  • 5,113

3 Answers3

5

Global variables are fine. They do make the dataflows less transparent, but for dataflows between distant components they can be a good tradeoff. Since you are writing an application and not a library, there's only a single “client” or context for those variables and keeping some global state is fine. Even for a library, global state representing the outside system configuration may be appropriate.

You can take steps to limit the downsides of using such global variables, namely keeping them as non-variable as possible. Consider offering access to the data only through an API that guarantees:

  1. the data can never be accessed in an uninitialized state (e.g. normal singleton initialization patterns ensure this)
  2. the data cannot be mutated by anyone else (e.g. provide methods for extracting essential information, or provide immutable views on the data structures)

Most dependency injection containers are not an alternative to global variables, they are an implicit global context. These DI containers merely offer a convenient interface for managing global configuration state.

amon
  • 135,795
3

Kind of guessing at what you mean here, I read it like this:

option 1: Global Variable

class UI
{
    Display()
    {
         Global.BigMap.Child.Child.Value < 10 ? displayComponent : dont
    }
}

option 2: Polluting interface

class UI
{
    private injectedBigMap
    Display()
    {
         injectedBigMap.ShouldDisplayComponent() ? displayComponent : dont
    }
}

I would go for a mix

class UIOptions : IUIOptions
{
     private injectedBigMap;
     ShouldDisplayComponent()
     {
         return injectedBigMap.Child.Child.Value < 10;
     }
}

class UI
{
    private injectedIUIOptions
    Display()
    {
         injectedIUIOptions.ShouldDisplayComponent() ? displayComponent : dont
    }
}

Now I can make a many IOptions for each class that needs one, separating the BigMap data and the logic of what it means from the component. But I keep a single BigMap and just pass the reference around, a 'global' variable but with scoped reference

If the BigMap changes I just need to adjust the Option classes. I can also mock them for testing.

EDIT

Just read your unity comment about passing the container around? This is a known anti pattern. But I'm confused as to why you would need to do it. Unity has built in support for dynamically loading classes and registering them via XML config.

Plus the whole point of having a container is that it resolves the dependencies for you automatically.

so in this case you can have

public class UI
{
    public UI(IUIOptions options)
    {
        this.options = options
    }
}

Main()
{
    container.Register<IUIOptions, UIOptions>()
    container.Register<UI>()

    var UI = container.Resolve<UI>(); //UIOptions automatically passed in!
}

Not...

public class UI
{
    public UI(IUnityContainer container)
    {
        this.options = container.Resolve<IUIOptions>(); //bad!!
    }
}

this way the calling class has no way to know what the dependencies are

Also, as I say Unity has the now rarely used xml config option, you can specify all your registrations dynamically in your app config

<alias alias="UIOptions" type="Plugin.UIOptions, Plugin.UIOptions" />
<alias alias="UI" type="Plugin.UI, Plugin.UI" />
<container>
   <register type="IUIOptions" mapTo="UIOptions"/>
   <register type="UI" mapTo="UI"/>
</container>
Ewan
  • 83,178
3

Generally, global variables are only really "bad", when you have too many of them and they are publicly mutable.

In this case, it sounds like you have a single service class needed by the whole application. Any dependency injection framework would definitely be overkill in my opinion, as they are built to handle systems that have hundreds of interconnected service dependencies.

Typically, service-style classes (like the one you describe) end up being public static on the Program class (console application) or App class (WPF/Winforms application).

The key is that the members of the service class are not static; instead, it should be a normal class that can be created and initialized, and then the instance of the service class is stored in a public static field/property so that the rest of the application can access it.

A good question to ask yourself whenever you're wondering if a global is appropriate would be: how hard would it be to modify this application to use two different implementations of this service?

If you have:

public static Program
{
    public static readonly SomeService SomeService { get; private set; }

    public static void Main()
    {
        SomeService = new SomeService();
        SomeService.Init();
    }
}

and all your code uses Program.SomeService, it would be relatively clean and easy to change it to:

public static Program
{
    public static readonly SomeService SomeService { get; private set; }

    public static readonly SomeService AnotherSomeService { get; private set; }

    public static void Main()
    {
        SomeService = new SomeService();
        SomeService.Init();

        AnotherSomeService = new SomeService();
        AnotherSomeService.Init();
    }
}

and change whatever code needs this other instance to use Program.AnotherSomeService.

One thing to keep in mind when you have a service class that permeates your entire application like this though, is that you will almost certainly need to make any mutation of internal service state thread-safe via locks or some other synchronization strategy.