Daniel Hoelbling-Inzko talks about programming
I 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.