The idea of creating a private object
to lock on is to ensure that your type, and only your type, is locking on that object. If you lock on some object that is available in other classes, then you need to consider what those other classes are doing with that object, and when they are locking on it, when trying to reason about what can possibly happen when your code is executing. If you lock on something like say, this
, or a public property/field, then you need to consider the possibility that any code, anywhere in the entire application, could possibly lock on that object. That makes it actually quite hard to reason about the code, to avoid deadlocks, etc.
The issue here is that the list (as far as you have shown) is never exposed outside of this class. If the list really is never exposed elsewhere, then nothing else can lock on it. If nothing else can lock on it, then there is no problem locking on it, and no real reason to create a second object
to lock on.
The goal of the SyncLock
is to explicitly allow types that haven't otherwise shared an object to lock on besides the list, to lock on that object. If you never expose the list elsewhere, nothing else will be able to grab that sync lock, so it's not really any different than locking on the list directly.
Of course, if you do expose the list externally (even if you cast it to something like an IEnumerable
, since that sill results in the same object reference to lock on) then options A and B are pretty much the same, and both should be avoided. The whole purpose of that pattern is to have something to lock on either if your type has no unchanging instance fields to lock on, or where they are exposed publicly. Although in some cases it's done just for the sake of readability, because people are so used to this pattern, and it's not that awful to create the object for just that reason, even though, as mentioned, it may not actually be necessary.