如何在C#中編寫實體比較器(帶有首次嘗試的示例代碼)

.net c# comparison entity-framework performance

可能重複:
比較兩個實體框架實體的最佳方法是什麼?

我想知道比較兩個相同類型實體的最有效方法。

一個實體是手工創建的xml文件(即新實例和手動設置屬性),另一個實體是從我的對像上下文中重新創建的。

我想知道每個實例中的屬性值是否相同。

我的第一個想法是從每個對像生成屬性值的哈希並比較哈希,但可能有另一種方式,或內置方式?

歡迎大家提出意見。

非常感謝,

詹姆士

UPDATE

我想出了這個:

static class ObjectComparator<T>
{
    static bool CompareProperties(T newObject, T oldObject)
    {
        if (newObject.GetType().GetProperties().Length != oldObject.GetType().GetProperties().Length)
        {
            return false;
        }
        else
        {
            var oldProperties = oldObject.GetType().GetProperties();

            foreach (PropertyInfo newProperty in newObject.GetType().GetProperties())
            {
                try
                {
                    PropertyInfo oldProperty = oldProperties.Single<PropertyInfo>(pi => pi.Name == newProperty.Name);

                    if (newProperty.GetValue(newObject, null) != oldProperty.GetValue(oldObject, null))
                    {
                        return false;
                    }
                }
                catch
                {
                    return false;
                }
            }

            return true;
        }
    }
}

我還沒有對它進行測試,從集團中產生更多的想法更能讓人深思。

可能存在問題的一件事是比較具有實體值本身的屬性,如果默認比較器在對象引用上進行比較,那麼它將永遠不會成立。可能的解決方法是重載我的實體上的相等運算符,以便它在實體ID上進行比較。

一般承認的答案

因為代碼不會做你期望的。

試試這個簡單的測試:


class A {
    public int Id { get; set; }
    public string Name { get; set; }
}

class B : A {
    public DateTime BirthDate { get; set; }
}

class ObjectComparer {
    public static void Show() {
        A a = new A();
        B b = new B();
        A a1 = new A();

        Console.WriteLine(ObjectComparator.CompareProperties(a, b));
        Console.WriteLine(ObjectComparator.CompareProperties(b, a));
        Console.WriteLine(ObjectComparator.CompareProperties(a, a1));
    }
}

你會期望它回來

真正

但它回來了

嘗試改變內部如果看起來像:


if (!object.Equals(newProperty.GetValue(newObject, null), oldProperty.GetValue(oldObject, null))) { 
       return false; 
} 

你也可以節省一些時間a和a1都通過在方法的開頭檢查它來引用同一個對象。


static class ObjectComparator { 
    public static bool CompareProperties(T newObject, T oldObject) {
        if (object.Equals(newObject, oldObject)) {
            return true;
        }
        if (newObject.GetType().GetProperties().Length != oldObject.GetType().GetProperties().Length) { 
            return false; 
        } 
        else { 
            var oldProperties = oldObject.GetType().GetProperties(); 
            foreach (PropertyInfo newProperty in newObject.GetType().GetProperties()) { 
                try { 
                    PropertyInfo oldProperty = oldProperties.Single(pi => pi.Name == newProperty.Name); 
                    if (!object.Equals(newProperty.GetValue(newObject, null), oldProperty.GetValue(oldObject, null))) { 
                        return false; 
                    } 
                } 
                catch { 
                    return false; 
                } 
            } 
            return true; 
        } 
    } 
}

如果您對性能有所了解,可以在方法的生命週期內將Type.GetProperties的返回緩存到局部變量中,因為Reflection至少不會在3.5 SP1版本之前自行完成。在這樣做時,您將GetProperties調用從四個調用到兩個。

如果您只希望比較完全相同類型的對象(或者在基本實例和派生實例之間進行另外的比較),則可以進一步將GetProperties的調用減少為1。

希望這可以幫助。


熱門答案

我會做這樣的事情

static class ObjectComparator<T>
{
    public static bool CompareProperties(T newObject, T oldObject)
    {
        if (Equals(newObject, oldObject))
        {
            return true;
        }
        PropertyInfo[] newProps = newObject.GetType().GetProperties();
        PropertyInfo[] oldProps = oldObject.GetType().GetProperties();

        if (newProps.Length != oldProps.Length)
        {
            return false;
        }

        foreach (PropertyInfo newProperty in newProps)
        {
            PropertyInfo oldProperty = oldProps.SingleOrDefault(pi => pi.Name == newProperty.Name);
            if (oldProperty == null)
                return false;

            object newval = newProperty.GetValue(newObject, null);
            object oldval = oldProperty.GetValue(oldObject, null);

            if (!Equals(newval, oldval))
                return false;
        }
        return true;
    }
}


許可下: CC-BY-SA with attribution
不隸屬於 Stack Overflow
這個KB合法嗎? 是的,了解原因
許可下: CC-BY-SA with attribution
不隸屬於 Stack Overflow
這個KB合法嗎? 是的,了解原因