The C# Language Specification can help answer this. The section on Execution Order has this to say:
3.10 Execution order
Execution of a C# program proceeds such that the side effects of each executing thread are preserved at critical execution points. ....The execution environment is free to change the order of execution of a C# program, subject to the following constraints:
Data dependence is preserved within a thread of execution. That is, the value of each variable is computed as if all statements in the thread were executed in original program order.
Initialization ordering rules are preserved (§10.5.4 and §10.5.5).
The ordering of side effects is preserved with respect to volatile reads and writes (§10.5.3).
(there is more that I've left out; the spec is quite readable so I suggest taking a look if you really want to get into the gritty details).
Essentially, the rules can be thought of as "the jitter may rearrange the execution order as long as the difference is not observable by the executing thread". But, other threads may observe the differences. In a post by Eric Lippert on the Coverity blog, he says:
...the CPU may as an optimization choose to [rearrange execution order] provided that doing so is not detectable by the current thread. But that fact could be observed by another thread...
So, if the order of operations is important for other threads as well as the current thread, then you'll need to create a "critical execution point"; the easiest way to do this is probably to surround the statements with a lock.