По-перше, відповіді Джона, Майкла та Джареда по суті правильні, але я маю ще кілька речей, які я хотів би до них додати.
Що мається на увазі під "нечистим" методом?
Легше охарактеризувати чисті методи. "Чистий" метод має такі характеристики:
- Його вихід повністю визначається вхідними даними; його вихід не залежить від зовнішніх факторів, таких як час доби або біти на жорсткому диску. Результат його роботи не залежить від його історії; виклик методу із заданим аргументом двічі повинен дати однаковий результат.
- Чистий метод не дає спостережуваних мутацій у навколишньому світі. Чистий метод може вибрати мутацію приватного стану заради ефективності, але чистий метод, скажімо, не мутує поле свого аргументу.
Наприклад, Math.Cos
це чистий метод. Його вихід залежить лише від його вводу, і вхід не змінюється під час дзвінка.
Нечистий метод - це метод, який не є чистим.
Які небезпеки передачі нечистим методам конструкцій лише для читання?
Є два, що спадають на думку. Перший - це той, на який вказали Джон, Майкл та Джаред, і це той, про який вас попереджає Решарпер. Коли ви викликаєте метод у структурі, ми завжди передаємо посилання на змінну, яка є одержувачем, на випадок, якщо метод хоче змінити змінну.
То що, якщо ви викликаєте такий метод за значенням, а не змінною? У цьому випадку ми робимо тимчасову змінну, копіюємо в неї значення і передаємо посилання на змінну.
Змінна лише для читання вважається значенням, оскільки вона не може бути мутована поза конструктором. Отже, ми копіюємо змінну в іншу змінну, і нечистий метод, можливо, мутує копію, коли ви маєте намір змінити її.
Ось небезпека передачі структури для читання як приймача . Також існує небезпека передачі структури, що містить поле лише для читання. Структура, що містить поле лише для читання, є загальноприйнятою практикою, але по суті, це написання чека про те, що система типу не має коштів для готівки; "лише читання" певної змінної визначається власником сховища. Екземпляр посилального типу "володіє" власним сховищем, але екземпляр типу значення - ні!
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);
Console.WriteLine(this.x);
}
}
Можна думати, що this.x
це не зміниться, оскільки x - це поле лише для читання і Badness
не є конструктором. Але ...
S s = new S(1);
s.Badness(ref s);
... наочно демонструє хибність цього. this
і s
посилаються на ту саму змінну, і ця змінна не лише для читання!