7

I have a class that handles the Localization of my application. My goal is that the class is usable in the entire application so I made it static. This allows me to call the code below anywhere in my application.

Localizer.GetString(/* Key to localize */)

The method uses several fields in the Localizer class. To make sure these fields are set, a Init method was added to initialize the Localizer. If the user of my class forgets to call Init at for example the start-up of the application, exceptions will occur because the fields are not set.

One solution I'm thinking about is making the Localizer class not static, add a constructor that sets the fields and initialize the class in a global static class in my application, something like this:

public static class Globals
{
    public static Localizer Localize = new Localizer(/* Field arguments here */);
}

Now I'm not sure what the best approach is. Either

  1. Static Localizer but user has to make sure Init is called before using the class.
  2. Instantiated Localizer in a global static class in the application.

One more note: The user has no access to the source of the class.

Krowi
  • 1,565
  • 3
  • 20
  • 40

1 Answers1

5

An alternative to what you're doing would be to use dependency injection. Dependency injection is a super fancy name for passing stuff into things instead of those things accessing that stuff directly. I know that's a vague statement - but if your class takes an argument for a field instead of creating the type itself - it's already using dependency injection.

So, let's say you have a Localizer class. It has no static methods and there is no static instance of a localizer just being global.

You create a Localizer instance specialized to your needs once when the app boots up:

var localizer = new Localizer(...);

Then, whenever a component needs the localizer - you pass it around

var component = new MyComponent(localizer); // we pass the values in

This makes the localizer easily modifiable, makes the classes easy to test in isolation and makes it easy to configure different components differently (what if you want the help page to always be in English all of a sudden? Or some other specific page?).

If it's still unclear here's a nice talk by Misko Havery about not looking for things. There is also a nice Martin Fowler article about it but it's probably a bit harder to follow.

The only tedious thing here is that you need to pass it around any time. I don't mind the explicitness but a lot of people prefer using dependency injection containers to manage the overhead.

Benjamin Gruenbaum
  • 270,886
  • 87
  • 504
  • 504
  • So if I understand it right, `var localizer` is a global variable like in my `Globals` class? – Krowi Apr 20 '15 at 06:22
  • @Krowi no, the entire point is that you don't have _any_ globals, global variables are bad and global mutable variables are worse. A singleton is _effectively_ a global variable - it's playing that role. So is a `static`. In your app there is a place where you bootstrap (start) it, you want to create the localizer _there_ and _pass it around_ instead of using global variables. – Benjamin Gruenbaum Apr 20 '15 at 06:23
  • @BenjaminGruenbaum The problem I think is that I'm working with Views and ViewModels. If I in VS in `App.xml.cs` (the start of the application I assume) create my instance of Localizer, how would I pass this around then to all the ViewModels? Now I have just ViewModels that are not dependent on each other or the application. – Krowi Apr 20 '15 at 06:30
  • @Krowi it's definitely possible to pass it around in WPF apps - lots of online tutorials on WPF and dependency injection :) – Benjamin Gruenbaum Apr 20 '15 at 07:11
  • @BenjaminGruenbaum I google a little and found a post here on SO that uses Ninject, another one on wpftutorial uses a `IUnityContainer` (which appear to be outdated according to MSDN and yet another post is using `IOC Containers` to do the job. I'm really confused with all the options and I'm not sure what the best solution is here for a MVVM WPF application. – Krowi Apr 20 '15 at 10:07
  • @Krowi being confused is a __good__ sign, this is a fundamental part of architecture you should understand and it's a differentiating factor - make sure you spend a few hours understanding DI, IoC and containers. See [this question for some alternatives people use](http://stackoverflow.com/questions/25366291/how-to-handle-dependency-injection-in-a-wpf-mvvm-application) – Benjamin Gruenbaum Apr 20 '15 at 10:15
  • @BenjaminGruenbaum From what I understand (without putting a lot of time in it yet) is that I first should learn what Interfaces are and how to use them. After that I should look up DI, IoC and containers and learn what they are. After that I should be able to make up my mind about how I want to build my application. Am I on the right track with this approach? *The SO link I mentioned was the one you linked :)* – Krowi Apr 20 '15 at 10:25
  • Yes, that sounds very reasonable to me – Benjamin Gruenbaum Apr 20 '15 at 10:27
  • @BenjaminGruenbaum I placed the following question here (http://stackoverflow.com/questions/29763594/dependency-injection-without-ninject) and is now solved. Would you consider this the correct way of using DI? If this is off topic, where should I ask this? – Krowi Apr 21 '15 at 06:04