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.