Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Consider implementing a short-circuiting fast path for quick comparison #41

Open
oising opened this issue May 9, 2022 · 8 comments
Open
Milestone

Comments

@oising
Copy link

oising commented May 9, 2022

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.

@reponemec
Copy link

reponemec commented May 9, 2022

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

@oising
Copy link
Author

oising commented May 9, 2022

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

Doesn't look like that to me:

  1. return (IEnumerable<Difference>)method.Invoke(comparer, new[] { obj1, obj2 });

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

@ValeraT1982
Copy link
Owner

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

@ValeraT1982 ValeraT1982 added this to the 2.0 milestone May 9, 2022
@reponemec
Copy link

@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?

@oising
Copy link
Author

oising commented May 10, 2022

@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.

@reponemec
Copy link

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
Copy link

reponemec commented May 16, 2022

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

@reponemec
Copy link

reponemec commented Jun 13, 2022

Up. @ValeraT1982

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants