Бред програміста ексепшени в task ах

Сьогодні розповім про чудових індусів з Microsoft. які спочатку роблять, а потім думають.

Конкретно мова піде про Таскі. Не буду про них розписувати, тому що не це тема сьогоднішнього поста. Якщо коротко, це такі треди на стероїдах зі смачними і зручними фічам.

Одна з фич, це кидок ексепшенов назовні. Приблизно так:


Тобто ми щось виконуємо в окремому потоці, в цей час займаємося своїми речами, а потім переконуємося, що таск закінчився і ловимо виняток, яке за нас обернули в AggregateException (справжнє приховано всередині його).
Тобто виходить цілком прикольна фіча, можна чесно ловити виключення з інших потоків в той час, коли ми знаємо, як їх обробити. І цим можна активно користуватися (наприклад, приховуючи всю паралельну роботу всередині методу, але пробрасивая виключення назовні).

Але є маленький нюанс. Ексепшен адже прокидати, коли від таска щось чекають (результат, або просто завершення). У стандартній термінології це називається observable. Тобто таск повинен бути контрольоване. А що якщо ми запустили і забули (або забили)?


Виходить, що ексепшен кудись загубиться? Як би не так! Доблесні фахівці з Microsoft подумали, і придумали кидати виключення в деструкції. Оцініть витонченість цього рішення: порушує всі осудні стандарти кодування, призводить до падіння додатки, і видає помилки в той час і в тому місці, де їх відловити неможливо взагалі. Супер!

Напевно, вони вирішили, що раз виняток в звичайному тред викликає падіння додатки, то і тут треба. Тільки забули про це маленька відмінність з винятками: якщо ми хочемо зробити безпечним звичайний тред, нам достатньо написати try / catch і всі стануть щасливі (все одно ніхто за нас помилки не обробить). А разі з ТАСК, кидати виняток зсередини назовні можна і місцями іноді корисно. Але виходить, що за цими ТАСК доводиться стежити як за маленькими дітьми, хоча нам цілком може бути глибоко наплювати в даному місці на результат конкретної операції.

Варіантів розв'язання проблеми в принципі можна придумати кілька (різні врапперов, стежити за використанням ТАСК), одне з досить красивих таке:


Тобто ми створюємо extension-метод, який прикріплює до нашої ТАСК продовження (continuation), в якому ми беремо значення властивості Exception (це обов'язково треба зробити! саме так таска стає знову спостерігається (observable)), і на цьому заспокоюємо систему.

Завдання вирішена, і сподіваюся, що у вас вона викличе мату менше ніж у мене свого часу, коли я попався на таку проблему. А попався я на неї ще з однієї причини.

Я спочатку не дарма писав, що в Microsoft спочатку зробили, а потім почали думати. А подумавши, вони зрозуміли, що поведінка аж надто ідіотське і вбивати все додаток нікому не потрібно. І в 4.5 змінили логіку, так що для 4.5 вже мій пост неактуальний.

Але без нюансів у Microsoft не обходиться, бо 4.5 за фактом підміняє собою 4.0. Сюрприз! Тобто встановивши 4.5, всі програми, написані під 4.0 починають за фактом працювати на 4.5, і злегка по-іншому. Наприклад, в даному випадку, помилка вже не з'явиться (трапляються і деякі інші відмінності в поведінці, але це вже занадто виражене). Повернути старе поведінка можна конфіг. але хто ж заморочується читанням усяких божевільних і непотрібних налаштувань?

Іноді просто хочеться вбитися головою об стіну від таких геніальних поворотів сюжету.