Коли я повинен використовувати оператор конверсії неявного типу C #?


14

У C # ми можемо перевантажити неявний оператор перетворення, як це (наприклад, з MSDN ):

struct Digit
{
    /* ... */
    public static implicit operator byte(Digit d)  // implicit digit to byte conversion operator
    {
        /* ... */
    }
}

Таким чином, ми можемо мати тип, тип власного значення , магічно перетворюючи себе в інший (неспоріднений) тип, залишаючи аудиторію здивованим (поки вони не заглянуть у куліси та не побачать неявного оператора перетворення, тобто).

Мені не подобається залишати нікого, хто читає мій код, здивовано. Я не думаю, що так багато людей.

Питання полягає в тому, які випадки використання оператора неявного типу перетворення, який не зробить мій код набагато складнішим для розуміння?


1
Ого. Я насправді не знав, що це існує. Не те, що це обов'язково добре використовувати; Я знаю, що люди справді роздратовані подібним функціоналом у C ++.
Катана314

@ Katana314: Це не людей дратувало, а про те, що хтось додає перевантаження (будь то оператор, функція перетворення, конструктор, вільна функція або член-функція) з дивовижною поведінкою, бажано тонко дивною.
Дедуплікатор

Я рекомендую вам прочитати інформацію про "перевантаження оператора" в C ++, зокрема операторів "лиття". Я підозрюю, що багато аргументів за / проти однакові, за винятком того, що дебати тривали тричі, поки C # існував ще багато для читання.

Відповіді:


18

Я б рекомендував лише неявні перетворення між типами, які приблизно представляють однакові значення по-різному. Наприклад:

  • Різні види кольору , як RGB, HSL, HSVі CMYK.
  • Різні одиниці для однієї фізичної величини ( Meterпроти Inch).
  • Різні системи координат (полярні та декартові).

Однак є кілька чітких вказівок, які вказують, коли не доцільно визначати неявну конверсію:

  • Якщо перетворення спричиняє значну втрату точності або діапазону, воно не повинно бути неявним (наприклад: від float64 до float32 або від long до int).
  • Якщо конверсія може кинути InvalidCastвиняток ( ), то це не повинно бути неявним.
  • Якщо перетворення викликає розподіл купи щоразу, коли воно виконується, воно не повинно бути неявним.
  • Якщо перетворення не є O(1)операцією, воно не повинно бути неявним.
  • Якщо тип джерела або цільовий тип є змінним, перетворення не повинно бути неявним.
  • Якщо конверсія залежить від якогось контексту (база даних, налаштування культури, конфігурація, файлова система тощо), це не повинно бути неявним (я б також відмовив від явного оператора перетворення в цьому випадку).

Тепер скажіть, що ваш оператор конверсії f: T1 -> T2не порушує жодне з наведених вище правил, то наступна поведінка наголошує, що конверсія може бути неявною:

  • Якщо a == bтоді f(a) == f(b).
  • Якщо a != bтоді f(a) != f(b).
  • Якщо a.ToString() == b.ToString()тоді f(a).ToString() == f(b).ToString().
  • І т. Д. Для інших операцій, визначених як на, так T1і на T2.

Усі ваші приклади, ймовірно, втрачають. Будь-то вони досить точні, ...
Дедуплікатор

Так, я зрозумів, що :-). Я не міг придумати кращого терміна для "програш". Те, що я мав на увазі під втратою, - це перетворення, де діапазон чи точність значно скорочуються. Наприклад, від float64 до float32 або від long до int.
Еліан Еббінг

Я думаю, що a! = B => f (a)! = F (b), ймовірно, не слід застосовувати. Існує безліч функцій, які можуть повернути одне і те ж значення для різних входів, floor () та ceil (), наприклад, на математичній стороні
cdkMoose

@cdkMoose Ви, звичайно, маєте рацію, і тому я вважаю ці властивості більше "бонусними балами", а не правилами. Друга властивість просто означає, що функція перетворення є ін'єктивною. Це часто трапляється при перетворенні на тип, який має суворо більший діапазон, наприклад, від int32 до int64.
Еліан Еббінг

@cdkMoose З іншого боку, перша властивість просто говорить, що два значення в межах одного класу еквівалентності T1(маються на увазі ==відношення on T1) завжди відображають два значення в межах одного класу еквівалентності T2. Тепер, коли я замислююся над цим, я думаю, що перше властивість насправді має бути необхідним для неявного перетворення.
Еліан Еббінг

6

Питання полягає в тому, які випадки використання оператора неявного типу перетворення, який не зробить мій код набагато складнішим для розуміння?

Коли типи не пов'язані (з програмістами). Є (рідкісні) сценарії, коли у вас є два неспоріднених типу (що стосується коду), які насправді пов'язані (що стосується домену чи розумних програмістів).

Наприклад, якийсь код, щоб зробити відповідність рядків. Загальний сценарій - відповідати рядковому буквалу. Замість того, щоб викликати IsMatch(input, new Literal("some string")), неявна конверсія дозволяє позбутися цієї церемонії - шуму в коді - і зосередитись на рядковому букве.

Більшість будь-яких програмістів побачать IsMatch(input, "some string")і швидко зрозуміють, що відбувається. Це робить ваш код чіткішим на сайті виклику. Коротше кажучи, це робить його трохи легше зрозуміти , що відбувається, в невеликій рахунок , як що відбувається.

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

І ви можете заперечити, що краще вимагати від програмістів явно створити проміжний тип, щоб вони побачили, "що насправді відбувається". Це менш прямолінійно. Особисто я вважаю, що приклад відповідності буквального рядка дуже чіткий щодо того, "що насправді відбувається" - програмісту не потрібно знати механіку того, як все відбувається. Чи знаєте ви, як весь ваш код виконується різними процесорами, на яких працює ваш код? Завжди є лінія абстракції, де програмісти перестають дбати про те, як щось працює. Якщо ви вважаєте, що неявні кроки перетворення важливі, тоді не використовуйте неявну конверсію. Якщо ви думаєте, що це просто церемонія, щоб радіти комп'ютеру, і програмісту було б краще не бачити цього шуму скрізь,


Ваша остання думка може бути і повинна бути прийнята ще далі: Існує також лінія, за якою програміст був проклятий, а краще не байдуже, як щось робиться, бо це не договірне.
Дедуплікатор
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.