문제

그 안에는 참조 루프가 포함되어 있지 않은 두 가지 대상을 감안할 때 (반사를 통해) "일반적인"방식으로 평등을 테스트하는 방법을 알고 있습니까?

나는 기본적으로 수업에서만 구조물 동등성과 동일한 의미를 원합니다.

도움이 되었습니까?

해결책

프레임 워크에는 그러한 방법이 없다고 생각하지만 상당히 쉽게 작성됩니다. 아마도 가장 짧은 구현은 아니지만 일을하는 것 같습니다.

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;

}

다른 팁

당신이 이것을하고 싶다면 없이 각 통화에 대해 반성하면 건축을 고려할 수 있습니다. DynamicMethod 첫 번째 호출 및 대신 사용합니다. (나는 이것을하는 기사에 대한 링크가 있었지만 그것을 잃어 버렸습니다 - 죄송합니다 - 관심이 있으면 인터넷 검색을 시도하십시오.)

BTW

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

동적 메소드 빌더로 사용할 수 있습니다.

Expreresison을 구축하는 동안 여전히 반사를 사용해야합니다

다음은 Fredrik Mörk의 답변에서 업데이트 된 버전입니다. Nullable 재귀 참조 :

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;
}
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top