Я хотів би детальніше зупинитися на конкретному питанні Еріка Ліпперта у своїй відповіді та поставити прожектор на певний випадок, який взагалі ніхто не торкався. Ерік сказав:
[...] призначення майже завжди залишає після себе значення, яке було щойно призначене в регістрі.
Я хочу сказати, що призначення завжди залишатиме після себе значення, яке ми намагалися присвоїти лівому операнду. Не просто «майже завжди». Але я не знаю, тому що я не знайшов цього питання, коментуваного в документації. Теоретично це може бути дуже ефективно реалізована процедура «залишити позаду» і не переоцінювати лівий операнд, але чи ефективна вона?
"Ефективний" так для всіх прикладів, побудованих на даний момент у відповідях цієї теми. Але ефективні у випадку властивостей та індексаторів, які використовують аксесуари для отримання та встановлення? Зовсім ні. Розглянемо цей код:
class Test
{
public bool MyProperty { get { return true; } set { ; } }
}
Тут ми маємо властивість, яка навіть не є обгорткою для приватної змінної. Кожного разу, коли він буде покликаний, він повернеться правдою, коли намагається встановити свою цінність, він нічого не робить. Таким чином, кожного разу, коли ця властивість оцінюється, він є правдою. Подивимося, що відбувається:
Test test = new Test();
if ((test.MyProperty = false) == true)
Console.WriteLine("Please print this text.");
else
Console.WriteLine("Unexpected!!");
Вгадайте, що це друкує? Це друкує Unexpected!!
. Як виявляється, встановлений аксесуар справді називається, що нічого не робить. Але після цього аксесуар отримати взагалі ніколи не викликається. Призначення просто залишає після себе false
значення, яке ми намагалися привласнити нашій власності. І це false
значення - це те, що якщо оператор if оцінює.
Я закінчу справжнім прикладом світу, який змусив мене дослідити цю проблему. Я зробив індексатор, який був зручною обгорткою для колекції ( List<string>
), яку мій клас мав як приватну змінну.
Параметр, надісланий індексатору, являв собою рядок, який повинен розглядатися як значення в моїй колекції. Access access просто поверне значення true або false, якщо це значення існувало у списку чи ні. Таким чином, отримати аксесуар був ще одним способом використання List<T>.Contains
методу.
Якщо встановлений аксесуар набору індексатора був вказаний рядком як аргументом, а правильний операнд - bool true
, він додасть цей параметр до списку. Але якби той самий параметр був надісланий аксесуару, а правий операнд - bool false
, він замість цього видалить елемент зі списку. Таким чином, встановлений аксесуар використовувався як зручна альтернатива як List<T>.Add
і List<T>.Remove
.
Я думав, що у мене є акуратний і компактний "API", який обгортає список за власною логікою, реалізованою як шлюз. За допомогою індексатора я міг зробити багато речей за допомогою декількох наборів клавіш. Наприклад, як я можу спробувати додати значення до свого списку та переконатися, що він там є? Я вважав, що це єдиний необхідний рядок коду:
if (myObject["stringValue"] = true)
; // Set operation succeeded..!
Але, як показав мій попередній приклад, отримати аксесуар, який повинен бачити, чи є в списку значення справді, навіть не називався. true
Значення завжди було залишено позаду ефективно знищуючи будь-яку логіку я здійснив в моєму ОТРИМАТИ аксессор.