Я не можу говорити за мовних дизайнерів, але, на чому я можу подумати, здається, це було навмисне, правильне дизайнерське рішення.
Переглядаючи цей базовий код F #, ви можете скласти це у робочу бібліотеку. Це юридичний код для F #, і лише перевантажує оператор рівності, а не нерівність:
module Module1
type Foo() =
let mutable myInternalValue = 0
member this.Prop
with get () = myInternalValue
and set (value) = myInternalValue <- value
static member op_Equality (left : Foo, right : Foo) = left.Prop = right.Prop
//static member op_Inequality (left : Foo, right : Foo) = left.Prop <> right.Prop
Це робить саме те, що виглядає. Він створює лише порівняльник рівності ==
і перевіряє, чи рівні внутрішні значення класу.
Поки ви не можете створити такий клас у C #, ви можете використовувати той, який був складений для .NET. Очевидно, що він буде використовувати наш перевантажений оператор для ==
Отже, для чого використовується час виконання !=
?
Стандарт C # EMCA містить цілу купу правил (розділ 14.9), де пояснюється, як визначити, який оператор використовувати при оцінці рівності. Якщо говорити про надмірно спрощений і, таким чином, не зовсім точний, якщо типи, які порівнюються, мають один і той же тип і присутній оператор перевантаженої рівності, він буде використовувати це перевантаження, а не стандартний оператор еталонної рівності, успадкований від Object. Тож не дивно, що якщо тільки один з операторів присутній, він використовуватиме оператор еталонної рівності за замовчуванням, який мають усі об'єкти, для нього не буде перевантаження. 1
Знаючи, що це так, справжнє питання: Чому це було розроблено таким чином і чому компілятор не з'ясував це самостійно? Дуже багато людей говорять, що це не було дизайнерським рішенням, але мені подобається вважати, що це було продумано таким чином, особливо стосовно того, що всі об'єкти мають оператора рівності за замовчуванням.
Отже, чому компілятор автоматично не створює !=
оператора? Я не можу точно знати, якщо хтось із Microsoft цього не підтвердить, але це я можу визначити з міркувань на фактах.
Щоб запобігти несподіваній поведінці
Можливо, я хочу зробити порівняння цінностей ==
для перевірки рівності. Однак, коли мова зайшла про !=
мене, то я взагалі не переймався, чи були рівні рівні, якщо посилання не було рівним, оскільки для моєї програми вважати їх рівними, мені цікаво лише, чи посилання відповідають. Зрештою, це насправді окреслюється як поведінка C # за замовчуванням (якщо обидва оператори не були перевантажені, як це було б у випадку з деякими бібліотеками .net, написаними іншою мовою). Якщо компілятор додавав код автоматично, я більше не міг би покладатися на компілятор для виведення коду, який повинен відповідати. Компілятор не повинен писати прихований код, який змінює вашу поведінку, особливо коли написаний вами код знаходиться в межах стандартів як C #, так і CLI.
З точки зору того, що він змушує вас перевантажувати його, замість того, щоб переходити до поведінки за замовчуванням, я можу лише твердо сказати, що це в стандарті (EMCA-334 17.9.2) 2 . Стандарт не вказує, чому. Я вважаю, що це пов'язано з тим, що C # запозичує багато поведінки у C ++. Детальніше про це див. Нижче.
Коли ви перекриєте !=
і ==
, вам не доведеться повертати bool.
Це ще одна вірогідна причина. У C # ця функція:
public static int operator ==(MyClass a, MyClass b) { return 0; }
діє як цей:
public static bool operator ==(MyClass a, MyClass b) { return true; }
Якщо ви повертаєте щось інше, ніж bool, компілятор не може автоматично зробити висновок протилежного типу. Крім того, в тому випадку , якщо ваш оператор робить зворотний BOOL, він просто не має сенсу для них створити генерувати код , який буде існувати тільки в тому , що один конкретний випадок або, як я вже говорив вище, код , який приховує поведінка за умовчанням CLR.
C # позичає багато з C ++ 3
Коли C # був представлений, в журналі MSDN з’явилася стаття, в якій написано, що розповідає про C #:
Багато розробників хочуть, щоб на мові було легко писати, читати та підтримувати, як Visual Basic, але це все ж забезпечувало потужність та гнучкість C ++.
Так, мета дизайну для C # полягала в тому, щоб надати майже стільки ж енергії, що і C ++, приносячи в жертву лише трохи зручностей, таких як жорстка безпека типу та збирання сміття. C # був сильно модельований після C ++.
Ви можете не здивуватися, дізнавшись, що в C ++ операторам рівності не потрібно повертати bool , як показано в цій прикладі програми
Тепер C ++ не вимагає від вас перевантажувати додаткового оператора. Якщо ваш компільований код у прикладі програми, ви побачите, що він працює без помилок. Однак якщо ви спробували додати рядок:
cout << (a != b);
ти отримаєш
помилка компілятора C2678 (MSVC): двійкова '! =': не знайдено жодного оператора, який приймає лівий операнд типу 'Тест' (або немає прийнятного перетворення) `.
Таким чином, хоча сам C ++ не вимагає перевантажувати вас парами, він не дозволить вам використовувати оператор рівності, який ви не перевантажували в користувацькому класі. Це дійсно в .NET, тому що всі об'єкти мають один за замовчуванням; C ++ не робить.
1. Як бічна примітка, стандарт C # все ж вимагає перевантажити пару операторів, якщо ви хочете перевантажити будь-якого. Це частина стандарту, а не просто компілятор . Однак ті самі правила щодо визначення того, якого оператора потрібно викликати, застосовуються під час доступу до бібліотеки .net, написаної іншою мовою, яка не має однакових вимог.
2. EMCA-334 (pdf) ( http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-334.pdf )
3. І Java, але тут справді не сенс