Generate hash of object consistently

后端 未结 3 548
忘了有多久
忘了有多久 2021-01-03 22:27

I\'m trying to get a hash (md5 or sha) of an object.

I\'ve implemented this: http://alexmg.com/post/2009/04/16/Compute-any-hash-for-any-object-in-C.aspx

I\'m

3条回答
  •  悲哀的现实
    2021-01-03 23:18

    If this 'hash' is solely used to determine whether entities have changed then the following algorithm may help (NB it is untested and assumes that the same runtime will be used when generating hashes (otherwise the reliance on GetHashCode for 'simple' types is incorrect)):

    public static byte[] Hash(T entity) 
    {
      var seen = new HashSet();
      var properties = GetAllSimpleProperties(entity, seen);
      return properties.Select(p => BitConverter.GetBytes(p.GetHashCode()).AsEnumerable()).Aggregate((ag, next) => ag.Concat(next)).ToArray();
    }
    
    private static IEnumerable GetAllSimpleProperties(T entity, HashSet seen)
    {
      foreach (var property in PropertiesOf.All(entity))
      {
        if (property is int || property is long || property is string ...) yield return property;
        else if (seen.Add(property)) // Handle cyclic references
        {
          foreach (var simple in GetAllSimpleProperties(property, seen)) yield return simple;
        }
      }
    }
    
    private static class PropertiesOf
    {
      private static readonly List> Properties = new List>();
    
      static PropertiesOf()
      {
        foreach (var property in typeof(T).GetProperties())
        {
          var getMethod = property.GetGetMethod();
          var function = (Func)Delegate.CreateDelegate(typeof(Func), getMethod);
          Properties.Add(function);
        }
      }
    
      public static IEnumerable All(T entity) 
      {
        return Properties.Select(p => p(entity)).Where(v => v != null);
      }
    } 
    
    
    

    This would then be useable like so:

    var entity1 = LoadEntityFromRdbms();
    var entity2 = LoadEntityFromNoSql();
    var hash1 = Hash(entity1);
    var hash2 = Hash(entity2);
    Assert.IsTrue(hash1.SequenceEqual(hash2));
    

    提交回复
    热议问题