En dyp struct-lignende lik () for .NET klasser?

stemmer
2

Gitt to innsigelser som ikke inneholder referansesløyfer i dem, vet du en metode som tester deres likestilling i en generisk måte (gjennom refleksjon)?

I utgangspunktet ønsker de samme semantikk som struct likeverdighet, bare på klasser.

Publisert på 17/05/2009 klokken 10:15
kilden bruker
På andre språk...                            


4 svar

stemmer
3

Jeg tror det er ingen slik metode tilgjengelig i rammen, men det er ganske lett skrevet. Kanskje ikke den korteste implementeringen men ser ut til å gjøre jobben:

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;

}
Svarte 17/05/2009 kl. 10:41
kilden bruker

stemmer
0

Her er en oppdatert versjon fra Fredrik Mörk svar som tar hensyn Nullableog rekursive referanser:

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;
}
Svarte 27/01/2017 kl. 09:39
kilden bruker

stemmer
0

BTW

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

kan brukes som en dynamisk metode bygger.

har fortsatt å bruke refleksjon samtidig bygge Expresison

Svarte 22/09/2009 kl. 18:02
kilden bruker

stemmer
0

Hvis du ønsker å gjøre dette uten å gjøre refleksjon på hver samtale, bør du kanskje vurdere å bygge en DynamicMethodpå første påkallelse og bruke det i stedet. (Jeg hadde en link til artikkelen som gjør dette, men jeg mistet den - beklager -. Prøv Googling hvis interessert)

Svarte 17/05/2009 kl. 10:46
kilden bruker

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more