Ответ 1
Во-первых, ответы Джона, Майкла и Джареда в основном правильны, но у меня есть еще несколько вещей, которые я хотел бы добавить к ним.
Что подразумевается под "нечистым" методом?
Легче охарактеризовать чистые методы. "Чистый" метод имеет следующие характеристики:
- Его вывод полностью определяется его входом; его выход не зависит от внешних факторов, таких как время суток или бит на жестком диске. Его выход не зависит от его истории; вызов метода с заданным аргументом дважды должен дать тот же результат.
- Чистый метод не производит наблюдаемых мутаций в окружающем его мире. Чистый метод может выбирать для того, чтобы мутировать частное состояние для эффективности, но чистый метод, скажем, не изменяет поле его аргумента.
Например, Math.Cos
- это чистый метод. Его выход зависит только от его ввода, и вход не изменяется при вызове.
Нечистый метод - это метод, который не является чистым.
Каковы некоторые из опасностей передачи readonly-структур на нечистые методы?
Есть два, которые приходят на ум. Первый - тот, который указал Джон, Майкл и Джаред, и это тот, о котором предупреждает вас Решар. Когда вы вызываете метод в struct, мы всегда передаем ссылку на переменную, которая является получателем, в случае, если метод хочет изменить эту переменную.
Итак, что, если вы вызываете такой метод по значению, а не по переменной? В этом случае мы создаем временную переменную, копируем в нее значение и передаем ссылку на переменную.
Переменная readonly считается значением, поскольку она не может быть изменена вне конструктора. Таким образом, мы копируем переменную в другую переменную, а нечистый метод, возможно, мутирует копию, когда вы намерены изменить ее.
Это опасность передачи структуры readonly как получателя. Существует также опасность передачи структуры, содержащей поле readonly. Структура, содержащая поле readonly, является обычной практикой, но в основном написана проверка того, что система типов не имеет денежных средств; "только для чтения" определенной переменной определяется владельцем хранилища. Экземпляр ссылочного типа "владеет" своим собственным хранилищем, но экземпляр типа значения не делает!
struct S
{
private readonly int x;
public S(int x) { this.x = x; }
public void Badness(ref S s)
{
Console.WriteLine(this.x);
s = new S(this.x + 1);
// This should be the same, right?
Console.WriteLine(this.x);
}
}
Кто-то думает, что this.x
не изменится, потому что x является полем только для чтения, а Badness
не является конструктором. Но...
S s = new S(1);
s.Badness(ref s);
... наглядно демонстрирует ложность этого. this
и s
относятся к одной и той же переменной, и эта переменная не является readonly!