Static members in generic classes
March 23, 2009 by Daniel HoelblingI have been using generics quite heavily lately for writing decorators to Repository classes that do logging and caching on top of the repository (I’ll talk about that another time).
Since I implemented an asynchronous cache clear method I immediately ran into some troubles with shared resources like the DB connection and so I figured the whole problem would be solved with a simple lock around the cache fill.
public class Cache<T> { private static readonly object locker = new object(); public IList<T> GetAll() { lock(locker) { //Query the DB etc.. return null; } } }
Maybe you already see the problem, but I for sure didn’t. And so it was quite a bit amazed when I discovered that the locking problem didn’t go away just like that.
Turns out, every generic class has it’s own static members. So Cache<string> has a different locker object than Cache<long> would have. Here’s the test to show this:
public class Test<T> { public static long calls; } public class Tester { [Fact] public void Calls_DifferentGenerics_DontShareInstance() { Test<string>.calls = 10; Test<long>.calls = 20; Assert.Equal(10, Test<string>.calls); Assert.Equal(20, Test<long>.calls); Assert.Equal(0, Test<int>.calls); } }
Since all of my Cache objects are singletons (enforced through Windsor), there is little point in locking there.
I solved this by having a non generic class containing the static lock object and going on, but I have to say that this bug could have gotten a rather hard to reproduce bug.