ObjectsComparer icon indicating copy to clipboard operation
ObjectsComparer copied to clipboard

Consider implementing a short-circuiting fast path for quick comparison

Open oising opened this issue 2 years ago • 8 comments

i.e. if I want to know if two objects are different, it would be good to have a short-circuiting boolean test method to return true if any difference (in practice, the first difference found) is detected.

I'm aware that bool Compare(a, b) exists, but it computes ALL changes every time when only the first is needed. For high performance scenarios, this has a significant overhead for larger objects.

oising avatar May 09 '22 02:05 oising

Comparer works with the "yield" keyword. Performance is therefore guaranteed in this way.

reponemec avatar May 09 '22 06:05 reponemec

Comparer works with the "yield" keyword. Performance is therefore guaranteed in this way.

Doesn't look like that to me:

  1. https://github.com/ValeraT1982/ObjectsComparer/blob/b106e48c467957dc3a41961345ed8769f0b3403a/ObjectsComparer/ObjectsComparer/Comparer.cs#L46

Later on the boolean Compare methods short-circuit with .Any() but at this point it's already compared the entire object.

oising avatar May 09 '22 12:05 oising

@oising you are right. Comparer always compare all differences. I'll think about improving it in the next versions.

ValeraT1982 avatar May 09 '22 15:05 ValeraT1982

@oising you are right. Comparer always compare all differences. I'll think about improving it in the next versions.

I thought it does not matter how a Compare ( => CalculateDifferences) operation is invoked (using reflection or not), i.e. yieldings should work as expected in both cases. Can you provide a simple test method?

reponemec avatar May 10 '22 11:05 reponemec

@oising you are right. Comparer always compare all differences. I'll think about improving it in the next versions.

I thought it does not matter how a Compare ( => CalculateDifferences) operation is invoked (using reflection or not), i.e. yieldings should work as expected in both cases. Can you provide a simple test method?

Try it yourself. Make two instances of an object with multiple properties. Have every property write a message to the console when the getter is called. Use Compare to validate.

edit: @reponemec my code snippet was misleading -- it's not the reflection that is significant.

oising avatar May 10 '22 17:05 oising

Try it yourself. Make two instances of an object with multiple properties. Have every property write a message to the console when the getter is called. Use Compare to validate.

I did it and only the first property seems to have been read:

[Test]
public void TestCompareEntireObject()
{
    var a1 = new TestClass { IntProperty = 10, StringProperty1 = "a", StringProperty2 = "b" };
    var a2 = new TestClass { IntProperty = 20, StringProperty1 = "b", StringProperty2 = "c" };

    //var comparer = new Comparer<TestClass>();
    var comparer = new Comparer();
    bool compareResult = comparer.Compare(a1, a2); //Only IntProperty.
    //bool calculateAnyDifferencesResult = comparer.CalculateDifferences(a1, a2).Any(); //Only IntProperty.
    //var diffsArray = comparer.CalculateDifferences(a1, a2).ToArray(); //All properties.

    /*
        IntProperty 10.
        IntProperty 20.
     */
}

public class TestClass
{
    int _intProperty;
    string _stringProperty1;
    string _stringProperty2;

    public int IntProperty 
    {
        get  
        {
            Debug.WriteLine($"IntProperty {_intProperty}.");
            return _intProperty; 
        } 

        set => _intProperty = value; 
    }

    public string StringProperty1
    {
        get
        {
            Debug.WriteLine($"StringProperty1 {_stringProperty1}.");
            return _stringProperty1;
        }

        set => _stringProperty1 = value;
    }

    public string StringProperty2
    {
        get
        {
            Debug.WriteLine($"StringProperty2 {_stringProperty2}.");
            return _stringProperty2;
        }

        set => _stringProperty2 = value;
    }
}

reponemec avatar May 11 '22 12:05 reponemec

Maybe I don't have the right test method, but it works as expected - the comparer only reads the first changed property .

reponemec avatar May 16 '22 12:05 reponemec

Up. @ValeraT1982

reponemec avatar Jun 13 '22 06:06 reponemec