Андрей прав; Я просто добавлю пару дополнительных деталей.
Во-первых, правильный подход к параметрам out / ref заключается в том, что они являются псевдонимами для переменных . То есть, когда у вас есть метод M (ref int q) и назовите его M (ref x), q и x равны двум разным именам для одной и той же переменной . Переменная является местом хранения; вы сохраняете что-то в q, вы также сохраняете это в x, потому что это два разных имени для одного и того же местоположения.
Во-вторых, альтернатива, которую вы описываете, называется ссылкой "копировать / копировать". В этой схеме есть два места хранения, и содержимое одного копируется в начало вызова функции и копируется обратно, когда это сделано. Как вы заметили, семантика копирование-в-копирование отличается от семантики ссылок псевдонимов при возникновении исключений.
Они также отличаются в странных ситуациях, подобных этому:
void M(ref int q, ref int r)
{
q = 10;
r = 20;
print (q);
}
...
M(ref x, ref x);
В псевдонимах x, q и r являются одним и тем же местом хранения, так что это печатает 20. При ссылках «копировать-в-копирование» это будет печатать 10, и окончательное значение x будет зависеть от того, будет ли копия -вый пошел слева направо или справа налево.
Наконец, если я правильно помню, существуют редкие и причудливые сценарии реализации деревьев выражений, в которых мы фактически реализуем семантику «копирование в копирование» для параметров ref. Я должен просмотреть этот код и посмотреть, смогу ли я вспомнить, что это за сценарии.