Last active
April 1, 2018 19:33
-
-
Save FleshMobProductions/fc4c6cf2026d63c00ae1a1529ef8e7bd to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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