Skip to content

Instantly share code, notes, and snippets.

@tocsoft
Created April 3, 2018 09:03
Show Gist options
  • Save tocsoft/25c389ca97b74b241c27a1ecd3b66c92 to your computer and use it in GitHub Desktop.
Save tocsoft/25c389ca97b74b241c27a1ecd3b66c92 to your computer and use it in GitHub Desktop.
Object Hasher
using Microsoft.CSharp.RuntimeBinder;
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Dynamic;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
namespace ObjectHash
{
public static class ObjectExtentions
{
static string nullHash = "".Hash();
public static string Hash<T>(this T @object)
=> @object.Hash(c => c);
public static string Hash<T, Y>(this T @object, Func<T, Y> projection)
{
Y target = default(Y);
if (@object != null)
{
target = projection(@object);
}
if (IsSimple(typeof(Y)))
{
return target?.ToString().Hash();
}
if(target == null)
{
return nullHash;
}
return target.ToDictionary().HashDictionary();
}
private static string HashDictionary(this Dictionary<string, object> dictionary)
{
var key = dictionary.GenerateKey();
return Hash(key);
}
private static string Hash(this string str)
{
var data = Encoding.Unicode.GetBytes(str);
var hasher = System.Security.Cryptography.SHA256.Create();
var hashData = hasher.ComputeHash(data);
return Convert.ToBase64String(hashData);
}
private static string GenerateKey(this Dictionary<string, object> dictionary)
{
StringBuilder sb = new StringBuilder();
InnerGenerateKey(dictionary, sb);
return sb.ToString();
}
private static void InnerGenerateKey(Dictionary<string, object> dictionary, StringBuilder sb)
{
var orderdKeys = dictionary.Keys.OrderBy(x => x);
foreach (var k in orderdKeys)
{
sb.Append('@');
sb.Append(k.Replace("@", "@@"));
sb.Append('@');
var val = dictionary[k];
if (val != null)
{
if (IsSimple(val.GetType()))
{
sb.Append(val.ToString());
}
else
{
InnerGenerateKey(val.ToDictionary(), sb);
}
}
}
}
private static bool IsSimple(Type type)
{
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>))
{
// nullable type, check if the nested type is simple.
return IsSimple(type.GetGenericArguments()[0]);
}
return type.IsPrimitive
|| type.IsEnum
|| type.Equals(typeof(string))
|| type.Equals(typeof(decimal))
|| type.Equals(typeof(DateTime));
}
///<summary>
/// Convert an object into a dictionary
///</summary>
///<param name="object">The object</param>
///<param name="nullHandler">Handler for null value</param>
///<returns></returns>
public static Dictionary<string, object> ToDictionary(this object @object)
{
if (@object == null)
{
return new Dictionary<string, object>();
}
var @objectAsDict = @object as IDictionary;
if (@objectAsDict != null)
{
var hashFromDict = new Dictionary<string, object>(@objectAsDict.Count);
foreach (var key in @objectAsDict.Keys)
{
hashFromDict.Add(key.ToString(), @objectAsDict[key]);
}
return hashFromDict;
}
var properties = TypeDescriptor.GetProperties(@object);
DynamicObject dyn = @object as DynamicObject;
int count = properties.Count;
List<string> dynNames = null;
if (dyn != null)
{
dynNames = dyn.GetDynamicMemberNames().ToList();
count += dynNames.Count;
}
var hash = new Dictionary<string, object>(count);
foreach (PropertyDescriptor descriptor in properties)
{
var key = descriptor.Name;
var value = descriptor.GetValue(@object);
hash.Add(key, value);
}
if (dynNames != null)
{
Type objType = @object.GetType();
foreach (string dynName in dynNames)
{
var key = dynName;
var value = GetValue(dynName, dyn, objType);
hash.Add(key, value);
}
}
return hash;
}
public static object GetValue(string name, DynamicObject dyn, Type objType)
{
try
{
var callSite =
CallSite<Func<CallSite, object, object>>.Create(
Microsoft.CSharp.RuntimeBinder.Binder.GetMember(CSharpBinderFlags.None, name, objType,
new[]
{
CSharpArgumentInfo.Create(
CSharpArgumentInfoFlags.None, null)
}));
return callSite.Target(callSite, dyn); ;
}
catch (RuntimeBinderException)
{
return null;
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment