Friday, April 29, 2011

StringDictionary as a common static list?

Hi, what I'm trying to do is have a project-wise static dictionary so I can access a single list from anywhere in my code.

Until now, I came up with this solution, a public static class with a public property:

public static class Common
{
    public static StringDictionary Domains
    {
        get
        {
            StringDictionary list = new StringDictionary();

            list.Add("212", "Location A");
            list.Add("555", "Location B");
            list.Add("747", "Location C");
            list.Add("000", "Location D");

            return list;
        }
    }
}

That I use in this way (I use it to replace the content of a cell in a gridview):

if (Common.Domains.ContainsKey(e.Row.Cells[5].Text))
{
    e.Row.Cells[5].Text = Common.Domains[e.Row.Cells[5].Text];
}
else
{
    e.Row.Cells[5].Text = "n/a";
}

But I don't know if this is an efficient solution, and/or if there are other (better) ways to do this... Can somebody give a hint?

Thanks in advance, Andrea.

From stackoverflow
  • Your dictionary is going to be reloaded every time you do a get on Domains

    Configure a static constructor that will load and stash a readonly static copy of the list instance dictionary in memory.

  • You probably don't want to re-create the list every time the property is accessed. Move the construction into the static constructor:

    public static class Common
    {
        private static StringDictionary _domains;
        static Common()
        {
            _domains = new StringDictionary();
            _domains.Add("212", "Location A");
            _domains.Add("555", "Location B");
            _domains.Add("747", "Location C");
            _domains.Add("000", "Location D");
        }
        public static StringDictionary Domains
        {
            get
            {
                return _domains;
            }
        }
    }
    

    And you should be aware, that the dictionary returned is not read-only. So a client of this class could modify the collection (e.g. add/remove some entries).

    Jeff Fritz : You beat me to writing the example..
    kappa : Thanks for your reply Martin, that's exactly what I was looking for!
    mnero0429 : You should also take into account all of the threading issues related to sharing a collection via a static field. This is a very tricky area, and I've elaborated more on it in my answer.
  • Consider using the Singleton pattern instead:

    http://en.wikipedia.org/wiki/Singleton_pattern

    It's not a must since every program has its own special needs , I only recommand you read about this pattern and rethink about your design again.

    If your program is multithreaded you might wanna check whether StringDictionary is thread safe , if it isn't thread safe (and your program is multithreaded), you should add some synchronization mechanism to your class.

    : Martin also posted some good points.
  • @Jeff Fritz is correct in his answer, but I just wanted to add a little more about the shared access of this field among multiple threads. StringDictionary is only thread-safe for read operations, and not write operations, so you'll want to be careful not to modify this collection without proper locking, and you'll also want to lock the collection when iterating over it.

    To iterate:

    lock(Common.Domains) {
        foreach(var domain in Common.Domains) {
        }
    }
    

    To add a domain outside the static constructor:

    lock(Common.Domains) {
        Common.Domains.Add("111", "Location 3");
    }
    

    In general, I'd be very careful when sharing a non-readonly collection via a static field so that the field isn't modified. You may want to make StringDictionary a ReadOnlyCollection instead and mark the field "readonly":

    public static readonly ReadOnlyCollection<Pair<string, string>> domains
    

    You won't get O(1) lookups, but I'm assuming this collection will be very small, so that won't matter anyway.

0 comments:

Post a Comment