Frage

Gibt es eine Standard-Implementierung, die IEqualityComparer<T> ReferenceEquals verwendet?

EqualityComparer<T>.Default verwendet ObjectComparer, die object.Equals() verwendet. In meinem Fall implementieren die Objekte bereits IEquatable<T>, die ich nur durch Objekt Bezug zu ignorieren und vergleichen müssen.

War es hilfreich?

Lösung

Nur für den Fall gibt es keine Default-Implementierung, das ist meine eigene:

Bearbeiten von 280Z28: Rationale für die Verwendung von RuntimeHelpers.GetHashCode(object) , die viele Sie haben wahrscheinlich noch nie zuvor gesehen. :) Diese Methode hat zwei Effekte, die es der richtig Aufruf für diese Implementierung machen:

  1. Es gibt 0 zurück, wenn das Objekt null ist. Da ReferenceEquals für null Parameter arbeitet, so sollte die Umsetzung des Vergleichs von GetHashCode ().
  2. Sie ruft Object.GetHashCode() nicht praktisch. ReferenceEquals ignoriert ausdrücklich jegliche Überschreibungen von Equals, so die Implementierung von GetHashCode () soll eine spezielle Methode, die die Wirkung von Referenceübereinstimmt, das ist genau das, was RuntimeHelpers.GetHashCode für ist.

[end 280Z28]

using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;

/// <summary>
/// A generic object comparerer that would only use object's reference, 
/// ignoring any <see cref="IEquatable{T}"/> or <see cref="object.Equals(object)"/>  overrides.
/// </summary>
public class ObjectReferenceEqualityComparer<T> : EqualityComparer<T>
    where T : class
{
    private static IEqualityComparer<T> _defaultComparer;

    public new static IEqualityComparer<T> Default
    {
        get { return _defaultComparer ?? (_defaultComparer = new ObjectReferenceEqualityComparer<T>()); }
    }

    #region IEqualityComparer<T> Members

    public override bool Equals(T x, T y)
    {
        return ReferenceEquals(x, y);
    }

    public override int GetHashCode(T obj)
    {
        return RuntimeHelpers.GetHashCode(obj);
    }

    #endregion
}

Andere Tipps

Ich dachte, es war Zeit, die bisherigen Antworten Implementierung .Net4.0 zu aktualisieren + wo es vereinfacht, indem er nicht generischen Dank auf der IEqualityComparer<in T> Schnittstelle zum Kontra:

using System.Collections;
using System.Collections.Generic;
using System.Runtime.CompilerServices;

public sealed class ReferenceEqualityComparer
    : IEqualityComparer, IEqualityComparer<object>
{
    public static readonly ReferenceEqualityComparer Default
        = new ReferenceEqualityComparer(); // JIT-lazy is sufficiently lazy imo.

    private ReferenceEqualityComparer() { } // <-- A matter of opinion / style.

    public bool Equals(object x, object y)
    {
        return x == y; // This is reference equality! (See explanation below.)
    }

    public int GetHashCode(object obj)
    {
        return RuntimeHelpers.GetHashCode(obj);
    }
}

Jetzt braucht es nur eine Instanz für alle Ihre Referenz-Gleichheit Überprüfung statt einer für jeden Typ T zu existieren, wie der Fall war vor.

Sie auch die Eingabe sparen, indem nicht jedes Mal, wenn Sie möchten, geben Sie T mit dieser verwenden!


für diejenigen Um zu klären, die nicht vertraut sind mit den Konzepten der Kovarianz und Kontra .. .

class MyClass
{
    ISet<MyClass> setOfMyClass = new HashSet<MyClass>(ReferenceEqualityComparer.Default);
}

... wird gut funktionieren. Dies ist nicht beschränkt auf z.B. HashSet<object> oder ähnlich (in .Net4.0).


Auch für jemanden fragen, warum x == y Referenz Gleichheit wird, ist es, weil der ==operator eine statische Methode ist, das heißt, es zur Compile-Zeit aufgelöst wird, und zum Zeitpunkt der Kompilierung x und y ist vom Typ object so ist es hier beschließt, der ==operator von object - das ist die real Referenz Gleichheit Methode. (In der Tat das Object.ReferenceEquals(object, object) Methode ist einfach eine Umleitung an den Objektoperator entspricht.)

Hier ist eine einfache Implementierung für C # 6.

public sealed class ReferenceEqualityComparer : IEqualityComparer, IEqualityComparer<object>
{
    public static ReferenceEqualityComparer Default { get; } = new ReferenceEqualityComparer();

    public new bool Equals(object x, object y) => ReferenceEquals(x, y);
    public int GetHashCode(object obj) => RuntimeHelpers.GetHashCode(obj);
}

Bearbeiten (Sie müssen dies nicht lesen, wenn Sie in den Kommentaren unten interessiert sind)

@AnorZaken gewidmet viele Absätze auf die drei Buchstaben des new Modifikator hier. Fassen wir zusammen.

Die einzige definierte Instanz Equals(object,object) Methode implementiert die Equals Verfahren der beiden erklärt Schnittstellen für diese Art, IEqualityComparer und seine generische Gegenstück IEqualityComparer<object>. Die Signaturen sind identisch, so dass diese Definition erfüllt beide Schnittstellen.

Die Instanzmethode ReferenceEqualityComparer.Equals(object,object) versteckt die statisch object.Equals(object,object) Methode.

Ohne new warnt der Compiler darüber. Was bedeutet das eigentlich bedeuten?

Es bedeutet, dass, wenn Sie die statische object.Equals Methoden aufrufen möchten, können Sie es nicht nennen kann auf eine Instanz von ReferenceEqualityComparer. Ist das ein Problem?

Nein. In der Tat ist es das Verhalten gewünscht. Es bedeutet, dass, wenn Sie object.Equals(a,b) anrufen möchten Sie es über den Code nicht tun können, wie ReferenceEqualityComparer.Default.Equals(a,b). Dieser Code anfordert eindeutig Hinweis Gleichheit - niemand würde vernünftigerweise erwarten, dass es default / Wertgleichheit durchzuführen. Warum sollen nicht codieren Sie nur den expliziten object.Equals(a,b) überhaupt? So ist die Verwendung von new bietet sinnvolle und wünschenswertes Verhalten und ermöglicht Kompilierung ohne Warnungen.

Wie sonst könnte man die Warnung unterdrücken? Wenn Sie eine #pragma warning disable 108 / #pragma warning restore 108 verwenden dann ist das Ergebnis das gleiche wie mit new, außer dass Sie ein paar mehr Lärm zu Ihrem Code hinzugefügt haben. new genügt und erklärt die Absicht deutlicher zu anderen.

Alternativ können Sie explizite Implementierungen für die beiden Schnittstelle Equals Methoden verwenden, aber dann, wenn Sie ReferenceEqualityComparer.Default.Equals(a,b) verwendet würden Sie nicht Verweis Gleichheit überhaupt haben.

In Wirklichkeit statische Methoden mit Instanzmethoden versteckt ist selten ein Problem, da statische Methoden von einem Typspezifizierer dereferenziert werden, keine Instanz Spezifizierer. Das heißt, Sie verwenden Foo.StaticMethod() nicht new Foo().StaticMethod(). Der Aufruf statische Methoden von Instanzen ist nicht notwendig, am besten und irreführend / falsch im schlimmsten Fall.

Ferner für die Gleichstellung comparers, Sie selten ihre konkreten Typen direkt verwenden. Vielmehr nutzen Sie sie mit APIs wie Sammlungen.

Während also das war eine interessante und manchmal verwirrend Diskussion, es war eher fruchtlos.

Microsoft bietet ObjectReferenceEqualityComparer in System.Data.Entity.Infrastructure. Verwenden Sie einfach ObjectReferenceEqualityComparer.Default als Vergleich.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top