Since the point of a lock is to protect some piece of memory, I think it would be useful to wrap that memory in a "Locked" object, and only make it accessble through the various lock tokens (as mentioned by Mark):
// Stores a private List<T>, only accessible through lock tokens
// returned by Read, Write, and UpgradableRead.
var lockedList = new LockedList<T>( );
using( var r = lockedList.Read( ) ) {
foreach( T item in r.Reader )
...
}
using( var w = lockedList.Write( ) ) {
w.Writer.Add( new T( ) );
}
T t = ...;
using( var u = lockedList.UpgradableRead( ) ) {
if( !u.Reader.Contains( t ) )
using( var w = u.Upgrade( ) )
w.Writer.Add( t );
}
Now the only way to access the internal list is by calling the appropriate accessor.
This works particularly well for List<T>, since it already has the ReadOnlyCollection<T> wrapper. For other types, you could always create a Locked<T,T>, but then you lose out on the nice readable/writable type distinction.
One improvement might be to define the R and W types as disposable wrappers themselves, which would protected against (inadvertant) errors like:
List<T> list;
using( var w = lockedList.Write( ) )
list = w.Writable;
//BAD: "locked" object leaked outside of lock scope
list.MakeChangesWithoutHoldingLock( );
However, this would make Locked more complicated to use, and the current version does gives you the same protection you have when manually locking a shared member.
sealed class LockedList<T> : Locked<List<T>, ReadOnlyCollection<T>> {
public LockedList( )