Frage

Da zwei einwenden, daß enthält keine Referenzschleife in sie, wissen Sie, eine Methode, die ihre Gleichheit in einer „allgemeinen“ Art und Weise testet (durch Reflexion)?

Ich mag im Grunde die gleiche Semantik wie struct Äquivalenz, nur auf Klassen.

War es hilfreich?

Lösung

Ich denke, es gibt kein solches Verfahren im Rahmen vorhanden ist, aber es ist ziemlich leicht geschrieben. Vielleicht nicht die kürzeste Umsetzung aber scheint die Arbeit zu tun:

private bool AreEqual(object x, object y)
{
    // if both are null, they are equal
    if (x == null && y == null)
    {
        return true;
    }
    // if one of them are null, they are not equal
    else if (x == null || y == null)
    {
        return false;
    }

    // if they are of different types, they can't be compared
    if (x.GetType() != y.GetType())
    {
        throw new InvalidOperationException("x and y must be of the same type");
    }

    Type type = x.GetType();
    PropertyInfo[] properties = type.GetProperties();

    for (int i = 0; i < properties.Length; i++)
    {
        // compare only properties that requires no parameters
        if (properties[i].GetGetMethod().GetParameters().Length == 0)
        {
            object xValue = properties[i].GetValue(x, null);
            object yValue = properties[i].GetValue(y, null);

            if (properties[i].PropertyType.IsValueType && !xValue.Equals(yValue))
            {
                return false;
            }
            else if (!properties[i].PropertyType.IsValueType)
            {
                if (!AreEqual(xValue, yValue))
                {
                    return false;
                }
            } // if
        } // if
    } // for

    return true;

}

Andere Tipps

Wenn Sie das tun möchten, ohne Reflexion bei jedem Aufruf zu tun, möchten Sie vielleicht den Aufbau einer DynamicMethod auf den ersten Aufruf zu prüfen, und die Verwendung dieser statt. (Ich hatte einen Link zu dem Artikel, der dies tut, aber ich verlor es - leider -. Versuchen, wenn interessiert googeln)

BTW

 Expression.Lambda<Func<T,T,bool>> Compile()

kann als dynamische Methode Builder verwendet werden.

noch Reflexion verwenden, während die Expresison Gebäude

Hier ist eine aktualisierte Version von Fredrik Mörk Antwort, die berücksichtigt Nullable und rekursive Referenzen nimmt:

public static bool AreEqual<T>(T x, T y) =>
    AreEqual(x, y, new HashSet<object>(new IdentityEqualityComparer<object>()));

private static bool AreEqual(object x, object y, ISet<object> visited)
{
    // if both are null, they are equal
    if (x == null && y == null) return true;

    // if one of them are null, they are not equal
    if (x == null || y == null) return false;

    // if they are of different types, they can't be compared
    if (x.GetType() != y.GetType())
    {
        throw new InvalidOperationException("x and y must be of the same type");
    }

    // check for recursive references
    if (visited.Contains(x)) return true;
    if (visited.Contains(y)) return true;
    visited.Add(x);
    visited.Add(y);

    var type = x.GetType();
    var properties = type.GetProperties();

    foreach (var property in properties)
    {
        // compare only properties that requires no parameters
        if (property.GetGetMethod().GetParameters().Length == 0)
        {
            object xValue = property.GetValue(x, null);
            object yValue = property.GetValue(y, null);

            if (property.PropertyType.IsValueType)
            {
                // check for Nullable
                if (xValue == null && yValue == null) continue;
                if (xValue == null || yValue == null) return false;
                if (!xValue.Equals(yValue)) return false;
            }

            if (!property.PropertyType.IsValueType)
            {
                if (!AreEqual(xValue, yValue, visited)) return false;
            }
        }
    }

    return true;
}

private class IdentityEqualityComparer<T> : IEqualityComparer<T> where T : class
{
    public int GetHashCode(T value) => RuntimeHelpers.GetHashCode(value);
    public bool Equals(T left, T right) => left == right;
}
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top