I am trying to use some code that will generate hashcode based on the value of all properties inside an object, but the following returns a 0 for the HashCodeOnProperties
Console.WriteLine("Hello, World!");
var request = new Request()
{
NorthEastLatitude = 43.13306116240615,
NorthEastLongitude = -80.9355926513672,
NorthWestLatitude = 43.13306116240615,
NorthWestLongitude = -81.573486328125014,
SouthEastLatitude = 42.831667202614092,
SouthEastLongitude = -80.9355926513672 ,
SouthWestLatitude = 42.831667202614092,
SouthWestLongitude = -81.573486328125014
};
var hash = request.GetHashCodeOnProperties();
Console.WriteLine(hash);
Console.ReadKey();
public class Request
{
public double? SouthWestLatitude { get; set; }
public double? SouthWestLongitude { get; set; }
public double? NorthEastLatitude { get; set; }
public double? NorthEastLongitude { get; set; }
public double? SouthEastLatitude { get; set; }
public double? SouthEastLongitude { get; set; }
public double? NorthWestLatitude { get; set; }
public double? NorthWestLongitude { get; set; }
}
public static class HashCodeByPropertyExtensions
{
public static int GetHashCodeOnProperties<T>(this T inspect)
{
return inspect.GetType().GetProperties().Select(o => o.GetValue(inspect)).GetListHashCode();
}
public static int GetListHashCode<T>(this IEnumerable<T> sequence)
{
return sequence
.Where(item => item != null)
.Select(item => item.GetHashCode())
.Aggregate((total, nextCode) => total ^ nextCode);
}
}
>Solution :
You are xoring values without "offset", so this will result in same values canceling each other out (exclusive or is associative and commutative so 42 ^ 77 ^ 42 ^ 77 is equivalent to 42 ^ 42 ^ 77 ^ 77 which is clearly is 0). You can do something like:
public static int GetListHashCode<T>(this IEnumerable<T> sequence)
{
var hash = 17;
return sequence
.Where(item => item != null)
.Select(item => item.GetHashCode())
.Aggregate(hash, (total, nextCode) => unchecked(total*23 + nextCode));
}
Or use System.HashCode (available since .NET Core 2.1) to perform aggregation:
public static int GetListHashCode<T>(this IEnumerable<T> sequence)
{
var hashCode = new HashCode();
return sequence
.Where(item => item != null)
.Select(item => item.GetHashCode())
.Aggregate(new HashCode(), (code, i) =>
{
hashCode.Add(i);
return hashCode;
})
.ToHashCode();
}
P.S.
Calculating hashcode should be fast operation, while reflection is usually not very fast approach. Consider using source generators or some dynamic code compilation with expression trees (see for example this or this answers for some inspiration)