HiveBrain v1.2.0
Get Started
← Back to all entries
patterncsharpMinor

ResourceManager Singleton

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
singletonresourcemanagerstackoverflow

Problem

As I understand creating lots of resource managers in C# may be a bad idea so I thought that the best thing to do would be to create a singleton for this.

However, I'm not 100% if this is a good idea, or if this is a good way to implement it.

The main thing about the implementation I am unsure about is making the "Instance" private and creating number of static functions to expose the functionality. This means I can call Local.GetString instead of Local.Instance.GetString which is less clunky. I have not seen any singleton implementation which does this so I wonder if there is some problem with it.

I am also using locking but I don't see how to get around that so that is probably fine.

```
public class Locale
{
// using System.Lazy -- see http://msdn.microsoft.com/en-us/library/dd642331.aspx
static readonly Lazy lazy = new Lazy(() => new Locale(), true);
static readonly object _locker = new object();

Dictionary _managers;

public Locale()
{
_managers = new Dictionary();
}

static Locale Instance { get { return lazy.Value; } }

public static ResourceManager GetManager(Type resourceType)
{
return Instance.GetResourceManager(resourceType);
}

public static string GetString(Type resourceType, string name)
{
var manager = Instance.GetResourceManager(resourceType);
return manager.GetString(name);
}

public static string GetString(Type resourceType, string name, CultureInfo culture)
{
var manager = Instance.GetResourceManager(resourceType);
return manager.GetString(name, culture);
}

public static object GetObject(Type resourceType, string name)
{
var manager = Instance.GetResourceManager(resourceType);
return manager.GetObject(name);
}

public static object GetObject(Type resourceType, string name, CultureInfo culture)
{
var manager = Instance.GetResourceManager(resourceType);
return manager.GetObjec

Solution

The main thing about the implementation I am unsure about is making the "Instance" private and creating number of static functions to expose the functionality. This means I can call Local.GetString instead of Local.Instance.GetString which is less clunky. I have not seen any singleton implementation which does this so I wonder if there is some problem with it.

I don't think there's a problem with that. Your static methods are only doing things which otherwise the calling code would do.


I am also using locking but I don't see how to get around that so that is probably fine.

If your code is single-threaded then you don't need locking at all.

If your code is multi-threaded, perhaps you can construct the singleton before the multi-threading starts: for example by calling a static Locale.CreateInstance method in your program's Main (or from Application_Start if your code is ASP.NET).

If your code is multi-threaded then the non-static Locale methods must also be thread-safe: including your Locale._managers dictionary accessors, and your ResourceManager methods. ResourceManager is already documented as a thread-safe class.

An alternative to the explicit lock you implemented is to use the ConcurrentDictionary class instead of Dictionary, specifically its GetOrAdd method, something like:

ResourceManager GetResourceManager(Type resourceType)
{
    Func valueFactory =
        resourceType => new ResourceManager(resourceType);
    return managers.GetOrAdd(resourceType, valueFactory);
}


Stylistically, some people recommend auto-declaring variables types as var for example ...

var valueFactory = resourceType => new ResourceManager(resourceType);


... or simply ...

ResourceManager GetResourceManager(Type resourceType)
{
    return managers.GetOrAdd(resourceType, resourceType => new ResourceManager(resourceType));
}

Code Snippets

ResourceManager GetResourceManager(Type resourceType)
{
    Func<Type, ResourceManager> valueFactory =
        resourceType => new ResourceManager(resourceType);
    return managers.GetOrAdd(resourceType, valueFactory);
}
var valueFactory = resourceType => new ResourceManager(resourceType);
ResourceManager GetResourceManager(Type resourceType)
{
    return managers.GetOrAdd(resourceType, resourceType => new ResourceManager(resourceType));
}

Context

StackExchange Code Review Q#39735, answer score: 3

Revisions (0)

No revisions yet.