10

次のタイプを検討してください。

class A { }
class B { }
interface IC { }

A a = null; // the value doesn't matter - null or anything else, for all three
B b = null;
IC c = null;

以下はコンパイルされませ:

var x = a == b;

しかし、以下コンパイルされます(私が発見して驚いたように):

var x = a == c;

私が理解しているように、コンパイラはデフォルトの == 演算子を使用するようにフォールバックします。これはオブジェクトで定義されているため、引数に任意の型を受け入れます。IL は次のようになります ( の詳細は無視してくださいldfld)。

ldarg.0
ldfld class A a
ldarg.0
ldfld class IC c
ceq
stloc.0

つまり、参照の等価性を使用します。

私の質問:

  1. 言語設計の観点からすると、なぜこれが理にかなっているのですか? 私にはそうではなく、大きな落とし穴だと思います。

  2. これが実際に落とし穴である場合、コード分析はそれについて警告するべきではないでしょうか? (いいえ-そうではありません)。ちなみにReSharperにはこの機能があるようです

4

2 に答える 2

7

2 行目がコンパイルされる理由は、A から派生して IC を実装する別のクラスが存在する可能性があるためです。

public class D : A, IC {}
...
a = new D(); c = a; var t = a == c; //t = true;

クラスは 1 つのクラスからしか継承できないため、A が B の子孫でない限り、またはその逆でない限り、A と B の両方を継承するクラスを作成することはできません。

于 2013-02-04T23:01:45.037 に答える
4

a == bテストがコンパイルされない理由はtrue、2つのクラスが同じ階層にないため、コンパイラーがテストを実行できない可能性があることを知るのに十分な情報を持っているためです。したがって、これは、実際には定数である条件を誤って記述できないようにするコンパイラと同等です。

インターフェイスの比較のために、コンパイラはoperator==(object, object)使用できるものがあることを確認します。また、とは両方ともA暗黙IC的に変換可能であるためobject、実際に発生する必要があります。IC条件が本物であるように実装する別のタイプ(必ずしも参照タイプである必要はありません)が存在する可能性があります。

R#警告は私が感謝するものです。このページにあるように、インターフェースタイプ間の同等性の比較は、場合によってはやや疑わしいものであり、非常に説明的で、ソリューションに置き換えるのが簡単ですobject.ReferenceEquals。もちろん、等式演算子が過負荷になっている可能性があるため、テストに意味があるかもしれないという反論があります。または、もっと簡潔なスタイルで書いている人かもしれません。明らかに、コンパイラでそのような使用を禁止することはやや手間がかかります。

于 2013-02-04T23:06:44.080 に答える