How do you create a dynamic equality implementatio

2019-02-19 12:21发布

问题:

Say I have an object Person with the properties below:

    public class Person
    {
        public int ID { get; set; }
        public int EmployeeNo { get; set; }
        public string JobDescription { get; set; }
        public string Code { get; set; }
    }

How would I dynamically check the equality of specific properties by name?

eg.

var dynamicEqualityComparer = RetrieveDynamicEqualityComparer("ID", "JobDescription");
var intersectedPersons = listOfPerson1.Intersect(listOfPerson2, dynamicEqualityComparer);

The above snippit would use the default linq intersect method using the dynamically generated equality comparison method which only compares the fields "ID" and "JobDescription".

I would assume that something like this would have been easy to find, but so far have not been able to locate anything of the sort.

回答1:

Put this in your person class then with your instance you can call equals

    public override bool Equals(object obj)
            {
                return obj.ToString() == this.ToString();
            }

           public override int GetHashCode()
           {
               return this.ToString().GetHashCode();
           }

            public override string ToString()
            {
                string myState;
                myState = string.Format("[ID: {0};EmployeeNo : {1}; JobDescription: {2};Code :{3}]",ID,EmployeeNo,JobDescription,Code);
                return myState;
            }

since the override of tostring accounts for all state data,in override equals you simply leverage your own implementation of ToString().

public int Compare(Person x, Person y)
        {
            if (x.ID == y.ID && x.JobDescription == y.JobDescription) 
                return 0;

            return (x.ID > y.ID) ? 1 : -1;//here you put what condition to return here i put ID just
                                          //for clarity,if u want just return -1 for ex:
        } 

this is the implementation of the IComparer<> interface of type Person



回答2:

The solution I came to is below:

The equality comparer class looks like:

public class CustomPropertyEqualityComparer<T>: IEqualityComparer<T> where T : class
{
    private readonly string[] _selectedComparisonProperties;

    public CustomPropertyEqualityComparer(params string[] selectedComparisonProperties)
    {
        _selectedComparisonProperties = selectedComparisonProperties;
    }

    public bool Equals(T x, T y)
    {
        if (x != null && y != null && x.GetType() == y.GetType())
        {
            var type = x.GetType();

            var comparableProperties = new List<string>(_selectedComparisonProperties);

            var objectProperties = type.GetProperties();

            var relevantProperties = objectProperties.Where(propertyInfo => comparableProperties.Contains(propertyInfo.Name));

            foreach (var propertyInfo in relevantProperties)
            {
                var xPropertyValue = type.GetProperty(propertyInfo.Name).GetValue(x, null);

                var yPropertyValue = type.GetProperty(propertyInfo.Name).GetValue(y, null);

                if (xPropertyValue != yPropertyValue && (xPropertyValue == null || !xPropertyValue.Equals(yPropertyValue)))
                {
                    return false;
                }

            }
            return true;
        }
        return x == y;
    }

    public int GetHashCode(T obj)
    {
        var type = typeof(T);

        var objectProperties = type.GetProperties();

        return objectProperties.Sum(property => property.GetHashCode());
    }
}

To create this class, you pass in a list of strings representing the objects property names.

To call this class, I used the following bit of code:

var groupKey = new List<string> {"EmployeeNo", "ID"}.ToArray();
var customEqualityComparer = new CustomPropertyEqualityComparer<object>(groupKey);

This creates a custom equality comparer for any class with the properties "EmployeeNo" and "ID".

I used this comparer when checking if two tables contain the same entries where equality doesn't necessarily mean that every single field is equal..

var existInBothTables = table1.Intersect(table2, customEqualityComparer).ToList();