Ф>>>>>volatile запрещает оптимизации компилятора в отношении поля. В ином случае Disposed может вернуть false там, где должен быть true, потому что false может "застрять" в регистре, куда ранее была зачитана ячейка памяти.
MH>>>>MH>>>>internal bool Disposed => _disposed != 0;
MH>>>>
MH>>>>когда будет вызван гетер для Disposed — вариантов кроме как прочитать _disposed из памяти нет. не будет он из регистра читаться
Ф>>>Такие гарантии может дать только volatile, т.е. запрет оптимизаций.
MH>>нет. нет других вариантов для реализации этого метода кроме как генерировать ассемблерную инструкцию чтения памяти.
Ф>а завтра может быть пара из mov и cmp. Например потому, что это другой процессор, и там джиттер работает немного иначе.
mov — всё равно из памяти будет читать

то есть другого варианта нет

дело не в том как джиттер работает. дело в том что при передаче управления в метод-геттера в теле метода надо читать филд, из памяти.
MH>>volatile — актуальна, когда в рамках одного метода надо запретить компилятору оптимизации. вот в таком кейсе (в жирном методе с рядом обращений к филду) он вполне может после 1-го чтения, запомнить результат в регистре
MH>>и затем к нему обращаться.
Ф>Проблема как раз в том, что метод вполне себе может быть жирным, и ты это никак не можешь проконтролировать. Просто очередной программист напишет пяток Receive() и пару Send() — всё, приехали: вот он простор для компиляторных оптимизаций.
дак а я о чём? конечно может быть какой-то метод жирным и в нём ряд обращений к полю компилятор (а затем джит) заоптимит так что 1-й раз прочитается в регистр а затем из него.
но мы рассматриваем ситуацию топик-стартера, то есть речь об методе
internal bool Disposed => _disposed != 0;
этот метод не жирный. здесь единственный случай чтения поля, и его можно только прочитать из памяти. не тот случай когда нужен volatile.
более того — если посмотреть в целом на ситуацию, то volatile не нужен. т.к. даже если мы гарантированно прочитали память, то в следующий момент ( может даже ещё до выхода из геттера) _disposed может оказаться выставленным,
и вызывающая сторона ошибочно посчитает что ещё не диспозед, хотя уже диспозед. то есть volatile никак не предотвратит на 100% вызывающую Disposed сторону от ошибочного действия.