- the synchronization strategy is different between the ECMA and MS specifications (so you can't robustly mimic the compiler's lock behaviour)
- inside the type, += talks directly to the field and does not use the accessor (so you can't ask the compiler nicely if you can please use the thread-safe code that it wrote for you)
leaving you very few options (except manual backing delegate fields and manual synchronization) for writing properly thread-safe event code in some corner-cases (note: most events don't need this level of attention!).
Well interestingly enough, things have changed in 4.0; I must have missed the big announcement, but Chris Burrows has three posts covering this. The last is largely additional info, but the short version of the first two is:
- The generated code is no longer a "lock(this)" (or "lock(type)" for static) - it uses lock-free exchange to do away with this ugly requirement (amusingly, the ECMA spec always maintained that the "how" was an implementation detail; only the MS spec insisted on a specific pattern)
- Inside the type, += and -= now use the add and remove accessors respectively, not the fields
Basically, my previous problem-case would now have worked just fine. I feel vindicated, but also very happy that this has been fixed.
On a related note; if you aren't already aware, note that even "lock(someObj)" gets an overhaul in the 4.0 compiler - see Eric Lippert's post: Locks and Exceptions do not mix