0

私は .NET Reflector を調べていて、たとえば "String" のような参照型の場合、"==" 演算子の明示的なオーバーロードがあることに気付きました。

typeof(string).GetMethod("op_Equality", BindingFlags.Static | BindingFlags.Public)

戻り値: "==" 演算子の System.Reflection.MethodInfo。

その実装により、次のようなことはできません。

if("hi" == 3)  // compiler error, plus code would throw an exception even if it ran)

ただし、同じことが値型に対しても機能します。

if((int)1 == (float)1.0)  // correctly returns true
if((int)1 == (float)1.2)  // correctly returns false

.NET が型変換プロセスを内部で処理する方法を正確に把握しようとしているので、.NET Reflector で op_Equality() の実装を探していましたが、「int」にはありません。

typeof(int).GetMethod("op_Equality", BindingFlags.Static | BindingFlags.Public)

null を返します。

では、値型の「==」演算子のデフォルトの実装はどこにあるのでしょうか? リフレクションを介して呼び出すことができるようにしたい:

public bool AreEqual(object x, object y)
{
    if(x.GetType().IsValueType && y.GetType().IsValueType)
        return x == y; // Incorrect, this calls the "object" equality override
    else
        ...
}

編集#1:

私はこれを試しましたが、うまくいきませんでした:

(int)1 == (float)1;                          // returns true
System.ValueType.Equals( (int)1, (float)1 ); // returns false

編集#2:

これも試しましたが、愛はありません:

object x = (int)1;
object y = (float)1.0;

bool b1 = (x == y);                 // b1 = false
bool b2 = ((ValueType)x).Equals(y); // b2 = false

ValueType のこの .Equals 演算子は、この型チェック (.NET Reflector から取得) により機能しないと考えています。

ValueType.Equals(object obj)
{
    ...

    RuntimeType type = (RuntimeType) base.GetType();
    RuntimeType type2 = (RuntimeType) obj.GetType();
    if (type2 != type)
    {
        return false;
    }

    ...
4

5 に答える 5

2

== op_Equality値型のデフォルトの実装はどこですか?

==値型のデフォルトはありません。独自の値の型を書いてみてください

struct JustAnotherValueType
{
  public readonly int Field;
  public JustAnotherValueType(int f) { Field = f; }
}

あなたのタイプの2つの値xを作りyます。彼らと一緒に言ってみてくださいx == y。コンパイルされません。あなた言うことができます

(object)x == (object)y

ただし、これはボックス化 (xボックス 1 と呼びましょう) とボックス化y(ボックス 2) を実行し、2 つのボックスで参照比較を実行します。したがって、常に false を返します。したがって、それは役に立ちません。これが、 between two==(object x, object y)を使用するときにオーバーロードが自動的に選択されない理由です。==JustAnotherValueType

では、intとはどうなっているfloatでしょうか。それらをC#で比較できますが、メソッド==がありません?! op_Equality説明は、これらのオーバーロードがC# 言語仕様で定義されているということです。セクション整数比較演算子および浮動小数点比較演算子 を参照してください。

実際には、これらの演算子は .NET 構造体のメンバーとして存在しませんが、C# 言語仕様で定義されており、C# コンパイラはそれらの動作を模倣するために有効な IL を生成する必要があります。

ちなみにどちらもSystem.Objectありませんop_Equality。これも C# でのみ定義されています。セクション参照型等値演算子を参照してください。には、コンパイラがこのオーバーロードを変換するために選択する可能性のあるメソッドがあることに注意しSystem.Objectてください。また、仕様のこのセクションでは制限が設けられているため、 はまたはに対してボクシングを実行しないことに注意してください。ReferenceEquals==x == yxy

C# 仕様には記載されていないが、 の使用が合法であるDateTimeTimeSpan、 などの値型はどうですか? 答えは、これらにメンバーがあるということです。Guid==op_Equality

結論: C# 言語仕様では、==C# の実装に必要な多くのオーバーロードが定義されており、これらのオーバーロードの一部にはintandfloatとが含まれobjectます。

注: 仮想インスタンス メソッドEquals(object)は、すべての値型で定義されobject、継承されます。このメソッド自体をオーバーライドしない構造体の場合、overrideinSystem.ValueTypeが使用されます。値で比較します。したがって、x上記yのように、x.Equals(y)正常に動作します。Equals仮想インスタンス メソッドです。一方、2 つのオペランドのコンパイル時の型に基づいてオーバーロード解決が実行される「メソッド」があります (「仮想ディスパッチ」はありません) ==static

于 2013-01-16T23:17:53.120 に答える
2

(int)1 == (float)1.0 の評価は、特別な == 演算子には依存せず、変換規則のみに依存します。

コンパイラはこれを (float)((int)1) == (float)1.0 に変換します。

編集: ルールはMSDNで指定されています。

于 2009-05-13T19:38:30.487 に答える
2

あなたが探しているのはValueType.Equalsです

多くの場合、これは値を少しずつ比較するだけです。場合によっては、リフレクションを使用してフィールドを検証します。

編集

C# が値の型を比較す​​る方法と、.Net が値の型を比較す​​る方法を混乱させています。ValueType.Equals は、同じ型を持つ値型オブジェクトを比較するために使用される .Net の関数です。C# は、最終的にその関数を呼び出すコードを出力します。ただし、「int」と「float」では呼び出しません。代わりに、最初に両方の値の精度を失わない型 (double) に両方を変換してから、結果の double 値を比較します。これが、動作に違いが見られる理由です。

于 2009-05-13T19:39:10.127 に答える
1

構造体に継承されるValueType.Equals(object obj)を探していると思います。リフレクションを使用してすべてのフィールドを比較します。

于 2009-05-13T19:36:34.530 に答える
1

別の質問に対する私の答えは、ローターの実装を提供します。実際のコードは、ネイティブ コードとして CLR に実装されます。

具体的には:

// Compare the contents (size - vtable - sink block index).
BOOL ret = memcmp(
    (void *) (pThisRef+1), 
    (void *) (pCompareRef+1), 
    pThisRef->GetMethodTable()->GetBaseSize() - sizeof(Object) - sizeof(int)) == 0;
于 2009-05-13T19:57:29.800 に答える