私は言語デザイナーのために話すことはできませんが、私が推論できることから、それは意図的で適切な設計決定であったようです。
この基本的な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つしか存在しない場合、すべてのオブジェクトが持つデフォルトの参照等価演算子が使用され、オーバーロードがないことは驚くにあたりません。1
これが事実であることを知って、本当の質問は次のとおりです。なぜこれがこのように設計されたのか、なぜコンパイラーはそれを自分で理解しないのですか?これは設計上の決定ではないと多くの人が言っていますが、特にすべてのオブジェクトにデフォルトの等価演算子があるという事実に関して、私はこのように考えられたと思います。
では、なぜコンパイラは自動的に!=
演算子を作成しないのでしょうか?マイクロソフトの誰かがこれを確認しない限り、私は確実に知ることはできませんが、これは事実の推論から判断できるものです。
予期しない動作を防ぐため
おそらく、==
同等性をテストするために値の比較を行いたいと思います。ただし、!=
参照が等しくない限り、値が等しいかどうかはまったく気になりませんでした。これは、プログラムがそれらを等しいと見なすために、参照が一致するかどうかのみを気にするためです。結局のところ、これは実際にはC#のデフォルトの動作として概説されています(別の言語で記述された.netライブラリの場合のように、両方の演算子がオーバーロードされなかった場合)。コンパイラーが自動的にコードを追加していた場合、準拠しているはずのコードを出力するためにコンパイラーに依存することができなくなりました。特に、作成したコードがC#とCLIの両方の標準の範囲内にある場合、コンパイラーは、自分の動作を変更する非表示のコードを作成しないでください。
デフォルトの動作に行くのではなく、オーバーロードすることを強制するという点で、私はそれが標準(EMCA-334 17.9.2)2にあると断言できます。規格はその理由を明記していません。これは、C#がC ++から多くの動作を借用しているためだと思います。これについて詳しくは、以下を参照してください。
!=
and をオーバーライドする場合==
、boolを返す必要はありません。
これはもう1つの理由です。C#では、この関数は:
public static int operator ==(MyClass a, MyClass b) { return 0; }
これと同じくらい有効です:
public static bool operator ==(MyClass a, MyClass b) { return true; }
bool以外のものを返す場合、コンパイラは反対の型を自動的に推測できません。さらに、オペレーターがブール値を返す場合、その特定のケースにのみ存在する生成コードを作成することや、前述のように、CLRのデフォルトの動作を非表示にするコードを作成しても意味がありません。
C#はC ++ 3から多くを借りています
C#が導入されたとき、CMSについて述べているMSDNマガジンの記事がありました。
多くの開発者は、Visual Basicのように記述、読み取り、保守が簡単で、しかもC ++の能力と柔軟性を備えた言語が存在することを望んでいます。
はい、C#の設計目標は、C ++とほぼ同じ量のパワーを与えることでした。厳密な型の安全性やガベージコレクションなどの利便性のために少しだけ犠牲にしています。C#はC ++に基づいて強くモデル化されました。
この例のプログラムに示すように、C ++では、等値演算子はboolを返す必要がないことを知って驚かないかもしれません
現在、C ++では、補完演算子をオーバーロードする必要はありません。サンプルプログラムでコードをコンパイルすると、エラーなしで実行されることがわかります。ただし、行を追加しようとした場合:
cout << (a != b);
あなたが得るでしょう
コンパイラエラーC2678(MSVC):バイナリ '!=':タイプ 'Test'の左側のオペランドを取る演算子が見つかりません(または許容できる変換がありません) `。
C ++自体はペアでオーバーロードする必要はありませんしながら、そう、それはないでしょう、あなたがカスタムクラスにオーバーロードされていないことを等価演算子を使用してみましょう。すべてのオブジェクトにはデフォルトのオブジェクトがあるため、.NETでは有効です。C ++にはありません。
1.補足として、C#標準では、どちらかの演算子をオーバーロードする場合は、演算子のペアをオーバーロードする必要があります。これは標準の一部であり、単なるコンパイラではありません。ただし、同じ要件を持たない別の言語で記述された.netライブラリにアクセスする場合、呼び出す演算子の決定に関する同じルールが適用されます。
2. EMCA-334(pdf)(http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-334.pdf)
3.そしてJavaですが、それはここでは本当に重要ではありません