Giter VIP home page Giter VIP logo

Comments (8)

StephenCleary avatar StephenCleary commented on May 20, 2024

The Default comparer will forward to the IComparable<T> implementation. What behavior were you expecting?

from comparers.

amir734jj avatar amir734jj commented on May 20, 2024

This throws an exception

            var c1 = new Component
            {
                Weight = 0.7,
                AccWeight = 0.2
            };
            
            var c2 = new Component
            {
                Weight = 0.7,
                AccWeight = 0.2
            };

            var result = c1.Equals(c2);

from comparers.

StephenCleary avatar StephenCleary commented on May 20, 2024

Yes, the Default comparer forwards to IComparable<T>, which is implemented by the DefaultComparer, which is just Default, which forwards to IComparable<T>, ... So of course you're going to get a stack overflow exception.

Again, what behavior were you expecting?

from comparers.

amir734jj avatar amir734jj commented on May 20, 2024

I expected it to compare one property at a time and return true.

from comparers.

amir734jj avatar amir734jj commented on May 20, 2024

I may be wrong but I don't think using Equals method should never throw StackOverflowException regardless of implementation. It should return either true or false.

from comparers.

StephenCleary avatar StephenCleary commented on May 20, 2024

@amir734jj: Nito.Comparers does not reflect over all properties of types. That's rarely the desired behavior.

The Default() comparer is behaving appropriately. You would have the same exact problem with the .NET Comparer<T>.Default or EqualityComparer<T>.Default.

from comparers.

amir734jj avatar amir734jj commented on May 20, 2024

I understand. I am passionate about this subject because I spend too much time daily writing and maintaining Equals and GetHashCode methods. We don't necessarily need to use reflection every time. We can just create an Expression and compile it once.

   public class Component
    {
        public double AccumulatedWeight { get; set; }

        public double Weight { get; set; }
        
        public Nested NestedRef { get; set; }
    }
    
    public class Nested
    {
        public double NestedProp { get; set; }
    }
    
    class Program
    {
        static void Main(string[] args)
        {   
            var c1 = new Component
            {
                Weight = 0.7,
                AccumulatedWeight = 0.2,
                NestedRef = new Nested
                {
                    NestedProp = 223
                }
            };
            
            var c2 = new Component
            {
                Weight = 0.7,
                AccumulatedWeight = 0.2,
                NestedRef = new Nested
                {
                    NestedProp = 223
                }
            };

            var result = BuildEquals<Component>()(c1, c2);
            
            Console.WriteLine(result);
        }
        
        public static Func<T, T, bool> BuildEquals<T>()
        {
            return ((Expression<Func<T, T, bool>>) BuildEquals(typeof(T))).Compile();
        }

        public static Expression BuildEquals(Type type)
        {
            bool IsComplexType(Type nestedType)
            {
                return !nestedType.Namespace.StartsWith("System.Collections") && nestedType.IsClass;
            }
            
            var arg1 = Expression.Parameter(type);
            var arg2 = Expression.Parameter(type);
            
            var body = type
                .GetProperties()
                .Select(x =>
                {
                    if (IsComplexType(x.PropertyType))
                    {
                        return (Expression) Expression.Invoke(BuildEquals(x.PropertyType),
                            Expression.Property(arg1, x.Name),
                            Expression.Property(arg2, x.Name));
                    }
                    else
                    {
                        return Expression.Equal(Expression.Property(arg1, x.Name), Expression.Property(arg2, x.Name));
                    }
                })
                .Aggregate((x, y) => Expression.And(x, y));

            return Expression.Lambda(body, arg1, arg2);
        } 

from comparers.

StephenCleary avatar StephenCleary commented on May 20, 2024

You can use a similar approach to BuildEquals along with Nito.Comparers as such:

public static IFullEqualityComparer<T> BuildAllMembersEqualityComparer<T>()
{
    var result = EqualityComparerBuilder.For<T>().Null();
    var type = typeof(T);
    var parameter = Expression.Parameter(type);
    foreach (var prop in type.GetProperties())
    {
        var expression = Expression.Property(parameter, prop.Name);
        dynamic selector = Expression.Lambda(expression, parameter).Compile();
        dynamic childComparer = null;
        if (IsComplexType(prop.PropertyType))
            childComparer = ((MethodInfo)MethodBase.GetCurrentMethod()).MakeGenericMethod(prop.PropertyType).Invoke(null, null);
        result = EqualityComparerExtensions.ThenEquateBy(result, selector, childComparer);
    }
    return result;

    bool IsComplexType(Type nestedType) => !nestedType.Namespace.StartsWith("System.Collections") && nestedType.IsClass;
}

This code takes a similar approach as run-time comparers: starting with Null (everything is equivalent), and adding a ThenEquateBy clause for each member.

Using Nito.Comparers in this way, the same lambda expressions are used to implement both Equals and GetHashCode.

from comparers.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.