this questionから簡体字および可能性を処分したLinqPad(なしoffsensive)、このような単純なコンソールアプリケーションからの影響を与える:暗黙のメソッドグループの変換落とし穴(その2)
public class Program
{
static void M() { }
static void Main(string[] args)
{
Action a = new Action(M);
Delegate b = new Action(M);
Console.WriteLine(a == b); //got False here
Console.Read();
}
}
オペレータからの「偽」の結果上記のコードのCILでceq
(詳細は元の質問をご覧ください)。だから私の質問は:
なぜ==
はcall Delegate Equals
の代わりにceq
に翻訳されているのですか?
ここでは、デリゲートとアクションの間の(un)ラッピングについては気にしません。最後に、a == b
を評価するとき、aはタイプAction
であり、bはDelegate
である。スペックから:
7.3.4バイナリ演算子オーバーロード解決
opがオーバーロードバイナリ演算子であるフォームXオペアンプY、動作、Xは、X型の発現 であり、そしてyは
•オペレータop(x、y)の のXとYによって提供される候補ユーザー定義演算子のセットが決定されます。集合は、Xによって提供される候補演算子の と、Yによって提供される候補演算子 とから成り、それぞれが§7.3.5の規則を使用して決定される。 XとYが同じタイプの場合、またはXとYが共通の ベースタイプから派生した場合、共有候補演算子は の組み合わせでのみ発生します。
•候補ユーザー定義演算子のセットが でない場合、これは 操作の候補演算子のセットになります。そうでない場合、既定の2項演算子op の実装は、持ち上げられたフォームを含めて、操作の候補演算子の集合 になります。与えられた演算子の定義済みの実装 は、演算子 (§7.8から§7.12)の記述で指定されています。 は、引数リスト(X、Y)に対する最良オペレータ を選択するための候補オペレータのセットに適用され、このオペレータは の結果となりさ§7.5.3のオーバーロード解決規則•
過負荷解決プロセス。オーバーロードの解決方法 が1つの最適な演算子を選択できなかった場合、バインディング時エラーが発生します。型TおよびOPがオーバーロード演算子であり、Aは、引数リスト、候補ユーザ定義演算子のセットである操作オペレータOP(A)、与えられ
7.3.5候補ユーザ定義演算子
オペレータop(A)の によって提供されるTは、次のように決定されます。
•タイプ T0を決定します。 TがNULL可能タイプである場合、少なくとも一人のオペレータが適用される場合に、T0は、そうでなければT0 はT. T0内のすべてのオペレータOPの宣言と、そのような演算子のすべての持ち上げ 形態について
•に等しく、その基礎となるタイプである (7.5.3。1)の場合、 の候補演算子の集合は、T0の該当するすべての演算子で構成されます。
•T0がオブジェクトの場合、候補演算子のセットは空です。 T0は、型パラメータである場合
•そうでない場合は、T0が提供する候補オペレータのセットは、T0の直接基底クラス、またはT0の 有効な基底クラスによって提供される候補の演算子のセット あります。スペックから
、a及びbは、同じ基本クラスDelegate
を有する明らかDelegate
で定義されたオペレータルール==
は(オペレータ==は、本質的にDelegate.Equalsを呼び出す)ここで適用されるべきです。しかし、ユーザー定義演算子の候補リストが空で最後にObject ==
が適用されたように見えます。
(2)FCLコードはC#言語仕様に従うべきですか?いいえ、何か特別な扱いがあるので、私の最初の質問は無意味です。そして、私たちはこれらの質問に「オハイオ州、FCLの特別な扱いです。彼らはできないことをすることができます」と答えています。スペックは外部のプログラマ向けです。
そのため、値型のセマンティクスが必要なときには、 'Equals'を使用するのが最善です。 (潜在的に)壊れた演算子のオーバーロードのため。 – Groo
@Groo:まったく。とにかく、私は、 '意図していない参照比較の可能性があります。値の比較を行うには、右手側に「System.Action」と入力します。 –
ユーザ定義のクラス階層で同じことをしようとすると、カスタム '=='メソッドが呼び出されます。 – AakashM