سؤال

بالنظر إلى كائنين معترضين لا يحتويان على حلقات مرجعية بداخلهما، هل تعرف طريقة تختبر المساواة بينهما بطريقة "عامة" (من خلال الانعكاس)؟

أريد بشكل أساسي نفس الدلالات مثل تكافؤ البنية، فقط في الفصول الدراسية.

هل كانت مفيدة؟

المحلول

وأعتقد لا يوجد طريقة متاحة في هذا الإطار، لكنها مكتوبة بسهولة إلى حد ما. ربما هو لا يبدو أقصر التنفيذ ولكن للقيام بهذه المهمة:

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 عند الاستدعاء الأول واستخدام ذلك بدلاً من ذلك.(كان لدي رابط للمقال الذي يفعل ذلك، لكنني فقدته - آسف - حاول البحث في Google إذا كنت مهتمًا.)

وراجع للشغل

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

ويمكن استخدامها كوسيلة من وسائل البناء الحيوية.

لا يزال لديك لاستخدام انعكاس حين بناء Expresison

وهنا نسخة محدثة من الإجابة فريدريك مورك أن يأخذ بعين الاعتبار 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