C# – Storing Constant Complex Objects in an Enum-Like Structure

asp.net-mvcc

I'm creating an ASP.NET MVC application to work with data from an API that has a couple of different endpoints for different geographical regions. Each region has a name, an alphanumeric ID and a host URL. e.g.: Western Europe - WE1 - we.api.com.

There are less than a dozen regions and their values won't change, though regions might get added or removed in the future. I would like to store these in a maintainable way so that I can easily pass them as parameters to functions. e.g.: GetUserData("username", Region.WesternEurope, true).

I have used Enums for this before for APIs where endpoints were defined by a single value but I can't decide how to go about this. One option I've considered is creating an Enum with just the names and then mapping those to objects in a dictionary in a static class, but I'm not a very experienced programmer and I don't know if this would be a good idea.

Best Answer

You could do that like this:

class Region
{
    public string name { get; private set; }
    public string id { get; private set; }
    public string url { get; private set; }

    // private constructor
    Region() {}

    // static members
    public static Region WesternEurope = new Region() {
        name = "Western Europe",
        id = "WE1",
        url = "we.api.com"
    };
}

I think that the private constructor implies that instances can only be created from within the class, e.g. as static members, so you control what instances are created.


Eventually you could load the instances from an external source (data file, database, or registry).

Per Doc Brown's comment, below, you could implement this loading in a static constructor of the Region class (e.g. to load all regions), or implement such loading in a static get accessor as shown below (e.g. to load each region just in time, if and when it's accessed).


In a comment below, Rumen Georgiev suggested the following alternative (which is, IMO, more complicated, and unnecessary, and not thread-safe):

// static members
private static Region _westernEurope;
public static Region WesternEurope 
{
    get 
    {
        if (_westernEurope == null)
        {
            _westernEurope = new Region() 
            {
                name = "Western Europe",
                id = "WE1",
                url = "we.api.com"
            };
        }
        return _westernEurope;
    }
}

An alternative version, which is both thread-safe and still enables lazy initialization of WesternEurope, uses the Lazy<> type:

    private static Lazy<Region> _westernEurope = new Lazy<Region>(
        () => new Region() 
        {
            name = "Western Europe",
            id = "WE1",
            url = "we.api.com"
        });

    public static Region WesternEurope => _westernEurope.Value;

It's questionable whether this is worth doing in this case though as the overhead of creating the instances when Region is statically initialised is likely to be small.

Related Topic