Я не уверен, почему Microsoft не использует заблокированный флаг Disposing в не виртуальном методе dispose (с намерением, чтобы финализатор - если таковой - должен использовать тот же флаг). Ситуации, когда несколько потоков могут попытаться избавиться от объекта, редки, но это не запрещено. Это может произойти, например, с объектами, которые должны выполнять некоторую асинхронную задачу и выполнять очистку после себя, но которые могут быть уничтожены на ранней стадии, если это необходимо. Удаление объекта не должно происходить достаточно часто для того, чтобы Interlocked.Exchange мог иметь сколько-нибудь значимые эксплуатационные затраты.
С другой стороны, важно отметить, что, хотя защита Dispose от нескольких вызовов является ИМХО разумной политикой, недостаточно сделать Dispose действительно поточно-ориентированным. Также необходимо убедиться, что вызов Dispose для используемого объекта оставит все в хорошем состоянии. Иногда для этого лучше всего установить флаг «KillMeNow», а затем в блоке, охраняемом Monitor.TryEnter, «Удалить объект». Каждая подпрограмма (кроме Dispose), которая использует объект, должна получить блокировку во время работы, но проверить как до получения, так и после снятия блокировки, чтобы увидеть, установлен ли KillMeNow; если это так, выполните Monitor.TryEnter и выполните логику удаления.
Более серьезная проблема с созданием многопоточного IDisposable заключается в том, что Microsoft не указывает, что метод RemoveHandler события должен быть поточно-безопасным без риска взаимоблокировки. Часто это необходимо для IDisposable.Dispose, чтобы удалить обработчики событий; без гарантированного многопоточного способа сделать это почти невозможно написать поточно-безопасный Dispose.