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.
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
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();