首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >一致地生成对象的哈希

一致地生成对象的哈希
EN

Stack Overflow用户
提问于 2012-09-13 01:29:11
回答 2查看 45K关注 0票数 20

我正在尝试获取对象的散列(md5或sha)。

我已经实现了这个:http://alexmg.com/post/2009/04/16/Compute-any-hash-for-any-object-in-C.aspx

我正在使用nHibernate从数据库中检索我的POCOs。

在此上运行GetHash时,每次从数据库中选择和刷新它时都是不同的。我猜这是意料之中的,因为底层代理将会改变。

不管怎样,

有没有办法获得一个对象的所有属性的散列,每次都是一致的?

我曾想过在this.GetType().GetProperties上使用StringBuilder .....并创建一个散列,但这似乎效率很低?

作为附注,这是为了跟踪这些实体从一个数据库(关系型数据库)到NoSQL存储(比较散列值以查看对象在关系型数据库和非关系型数据库之间是否发生了变化)的更改。

EN

回答 2

Stack Overflow用户

发布于 2012-09-13 02:02:53

如果这个“散列”仅用于确定实体是否已更改,则以下算法可能会有所帮助(注意,它未经过测试,并假设在生成散列时将使用相同的运行时(否则,对“简单”类型的依赖GetHashCode是不正确的):

代码语言:javascript
运行
复制
public static byte[] Hash<T>(T entity) 
{
  var seen = new HashSet<object>();
  var properties = GetAllSimpleProperties(entity, seen);
  return properties.Select(p => BitConverter.GetBytes(p.GetHashCode()).AsEnumerable()).Aggregate((ag, next) => ag.Concat(next)).ToArray();
}

private static IEnumerable<object> GetAllSimpleProperties<T>(T entity, HashSet<object> seen)
{
  foreach (var property in PropertiesOf<T>.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<T>
{
  private static readonly List<Func<T, dynamic>> Properties = new List<Func<T, dynamic>>();

  static PropertiesOf()
  {
    foreach (var property in typeof(T).GetProperties())
    {
      var getMethod = property.GetGetMethod();
      var function = (Func<T, dynamic>)Delegate.CreateDelegate(typeof(Func<T, dynamic>), getMethod);
      Properties.Add(function);
    }
  }

  public static IEnumerable<dynamic> All(T entity) 
  {
    return Properties.Select(p => p(entity)).Where(v => v != null);
  }
} 

然后它就可以像这样使用了:

代码语言:javascript
运行
复制
var entity1 = LoadEntityFromRdbms();
var entity2 = LoadEntityFromNoSql();
var hash1 = Hash(entity1);
var hash2 = Hash(entity2);
Assert.IsTrue(hash1.SequenceEqual(hash2));
票数 11
EN

Stack Overflow用户

发布于 2012-09-13 04:28:32

GetHashCode()返回一个Int32 (不是MD5)。

如果您创建了两个具有所有相同属性值的对象,则如果您使用基本或系统GetHashCode(),它们将不会具有相同的哈希。

字符串是一个对象,也是一个异常。

代码语言:javascript
运行
复制
string s1 = "john";
string s2 = "john";
if (s1 == s2) returns true and will return the same GetHashCode()

如果你想控制两个对象的相等比较,那么你应该重写GetHash和相等。

如果两个对象相同,那么它们也必须具有相同的GetHash()。但是具有相同GetHash()的两个对象不一定相同。比较将首先测试GetHash(),如果它在那里得到匹配,它将测试相等。好的,有一些比较直接到相等,但你仍然应该覆盖这两个,并确保两个相同的对象产生相同的GetHash。

我用它来同步客户端和服务器。您可以使用所有属性,也可以更改任何属性来更改VerID。这里的优点是一个更简单、更快的GetHashCode()。在我的例子中,我已经通过任何属性更改重置了VerID。

代码语言:javascript
运行
复制
    public override bool Equals(Object obj)
    {
        //Check for null and compare run-time types.
        if (obj == null || !(obj is FTSdocWord)) return false;
        FTSdocWord item = (FTSdocWord)obj;
        return (OjbID == item.ObjID && VerID == item.VerID);
    }
    public override int GetHashCode()
    {
        return ObjID ^ VerID;
    }

我最终单独使用了ObjID,因此我可以执行以下操作

代码语言:javascript
运行
复制
if (myClientObj == myServerObj && myClientObj.VerID <> myServerObj.VerID)
{
   // need to synch
}

Object.GetHashCode Method

具有相同属性值的两个对象。它们是否相等?它们是否产生相同的GetHashCode()?

代码语言:javascript
运行
复制
            personDefault pd1 = new personDefault("John");
            personDefault pd2 = new personDefault("John");
            System.Diagnostics.Debug.WriteLine(po1.GetHashCode().ToString());
            System.Diagnostics.Debug.WriteLine(po2.GetHashCode().ToString()); 
            // different GetHashCode
            if (pd1.Equals(pd2))  // returns false
            {
                System.Diagnostics.Debug.WriteLine("pd1 == pd2");
            }
            List<personDefault> personsDefault = new List<personDefault>();
            personsDefault.Add(pd1);
            if (personsDefault.Contains(pd2))  // returns false
            {
                System.Diagnostics.Debug.WriteLine("Contains(pd2)");
            }

            personOverRide po1 = new personOverRide("John");
            personOverRide po2 = new personOverRide("John");
            System.Diagnostics.Debug.WriteLine(po1.GetHashCode().ToString());
            System.Diagnostics.Debug.WriteLine(po2.GetHashCode().ToString());  
            // same hash
            if (po1.Equals(po2))  // returns true
            {
                System.Diagnostics.Debug.WriteLine("po1 == po2");
            }
            List<personOverRide> personsOverRide = new List<personOverRide>();
            personsOverRide.Add(po1);
            if (personsOverRide.Contains(po2))  // returns true
            {
                System.Diagnostics.Debug.WriteLine("Contains(p02)");
            }
        }



        public class personDefault
        {
            public string Name { get; private set; }
            public personDefault(string name) { Name = name; }
        }

        public class personOverRide: Object
        {
            public string Name { get; private set; }
            public personOverRide(string name) { Name = name; }

            public override bool Equals(Object obj)
            {
                //Check for null and compare run-time types.
                if (obj == null || !(obj is personOverRide)) return false;
                personOverRide item = (personOverRide)obj;
                return (Name == item.Name);
            }
            public override int GetHashCode()
            {
                return Name.GetHashCode();
            }
        }
票数 -1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/12393467

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档