Skip to content

Instantly share code, notes, and snippets.

@FleshMobProductions
Last active April 1, 2018 19:33
Show Gist options
  • Save FleshMobProductions/fc4c6cf2026d63c00ae1a1529ef8e7bd to your computer and use it in GitHub Desktop.
Save FleshMobProductions/fc4c6cf2026d63c00ae1a1529ef8e7bd to your computer and use it in GitHub Desktop.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
public static class HashUtility {
private static Dictionary<Type, System.Reflection.FieldInfo[]> typeTovalueFieldInfoLookup;
static HashUtility()
{
typeTovalueFieldInfoLookup = new Dictionary<Type, System.Reflection.FieldInfo[]>();
InitializeDataTypeFields();
}
private static void InitializeDataTypeFields()
{
Type[] types = new Type[]{
//include the types that should be cached at the first class access here:
};
for (int i = 0; i < types.Length; i++)
{
if (!typeTovalueFieldInfoLookup.ContainsKey(types[i]))
{
CreateValueFieldInfosCached(types[i]);
}
}
}
public static FieldInfo[] GetValueFields(Type type)
{
if (!typeTovalueFieldInfoLookup.ContainsKey(type))
{
CreateValueFieldInfosCached(type);
}
return typeTovalueFieldInfoLookup[type];
}
//value types generate their hash code by the member fields, so it should be fine. We ignore class references
private static void CreateValueFieldInfosCached(Type type)
{
List<FieldInfo> valueFields = new List<FieldInfo>();
var fields = type.GetFields();
for (int i = 0; i < fields.Count(); i++)
{
var fieldInfo = fields[i];
//ensure that the field is public, because the documentation states that FieldType.GetValue checks to see if the user has access permission and will throw an error if not.
//Only include the value types. The default hash algorithm for value types in .NET uses the member variables and creates a hash by using reflection.
if (fieldInfo.FieldType.IsValueType && fieldInfo.FieldType.IsPublic)
{
valueFields.Add(fieldInfo);
}
}
valueFields.Sort(); //make sure that the order is the same on every machine? Can be skipped
typeTovalueFieldInfoLookup[type] = valueFields.ToArray();
}
public static int CreateValueFieldsHash<T>(this T value) {
Type t = value.GetType();
var fields = GetValueFields(t);
int hashCode = 47;
const int hashPrimeMultiplier = 17;
//ignore overflows
unchecked
{
for (int i = 0; i < fields.Count(); i++)
{
object fieldVal = fields[i].GetValue(value);
hashCode = (hashCode * hashPrimeMultiplier) + fieldVal.GetHashCode();
}
}
return hashCode;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment