2017-03-05 4 views
0

オブジェクトの一貫したGuidを作成する必要があります。私は同じプロパティを持つオブジェクトのためのユニークなGUIDを作成するアプローチの下に行くと思っている、何とか間違って感じる。オブジェクトの一貫したGuidの作成

class Person 
{ 
    public string Name { get; set; } 
    public int Age { get; set; } 

    public override string ToString() 
    { 
     return "Person: " + Name + " " + Age; 
    } 
} 

// Below tool is taken from http://stackoverflow.com/questions/2642141/how-to-create-deterministic-guids 
Guid guid = GuidUtility.Create(GLOBAL, new Person(..).ToString(); 

欲しい。

Map<Guid, serialized Object>を永続ストレージに保存し、新しいオブジェクトを作成するたびに、同じプロパティを持つオブジェクトが既に存在するかどうかを確認することでした。

RFC 4122認定者は、名前空間と名前ごとに決定論的で一意である可能性が高いです。 https://tools.ietf.org/html/rfc4122#page-13 お願いします。ありがとうございました

+0

私はなぜあなたが 'Guid'を使いたいのか分かりません。 –

+0

言い換えれば、なぜこのために 'Guid'を使うのですか? –

答えて

1

私はこの答えにハッシングアルゴリズムを使ってこれを考え出しました。GetHashCode明らかに、同じハッシュコードを持つ異なる値を持つオブジェクトに対して常に競合の問題があります。しかし、Guidの128ビットでは、潜在的に無限領域から非常に限定された領域、主に32ビットに変換するので、この問題は解決できません。あなたが言ったように、ルックアップテーブルを実装すると、起こる可能性はかなり低いにもかかわらず、この種の問題を回避するだけです。

public static class ConsistentGuid 
{ 
    public static System.Guid Generate(object obj) 
    { 
     var bytes = new byte[16]; 

     var type = obj.GetType(); 

     var features = new object[] 
     { 
      type, 
      obj 
     }; 

     BitConverter.GetBytes(LongHash(features)) 
      .CopyTo(bytes, 0); 

     var properties = type.GetProperties(BindingFlags.Public | BindingFlags.Instance); 
     features = new object[properties.Length]; 
     for (int i = 0; i < properties.Length; i++) 
      features[i] = properties[i].GetValue(obj); 

     BitConverter.GetBytes(LongHash(features)) 
      .CopyTo(bytes, 8); 

     return new System.Guid(bytes); 
    } 

    public static int Hash(object[] features, uint seed = 2166136261) 
    { 
     // https://stackoverflow.com/questions/263400/what-is-the-best-algorithm-for-an-overridden-system-object-gethashcode/263416#263416 
     unchecked // Overflow is fine, just wrap 
     { 
      int hash = (int)seed; 
      for (int i = 0; i < features.Length; i++) 
      { 
       if (features[i] == null) // Suitable nullity checks etc, of course :) 
        continue; 

       hash = (hash * 16777619)^features[i].GetHashCode(); 
      } 

      return hash; 
     } 
    } 

    private static long LongHash(object[] features, ulong seed = 2166136261) 
    { 
     // https://stackoverflow.com/questions/263400/what-is-the-best-algorithm-for-an-overridden-system-object-gethashcode/263416#263416 
     unchecked // Overflow is fine, just wrap 
     { 
      long hash = (long)seed; 
      for (int i = 0; i < features.Length; i++) 
      { 
       if (features[i] == null) // Suitable nullity checks etc, of course :) 
        continue; 

       hash = (hash * 16777619)^features[i].GetHashCode(); 
      } 

      return hash; 
     } 
    } 
} 

ここに渡されたテストです。

public class ConsistentGuidTests 
{ 
    [Fact] 
    public void Referencewise_Equal_Objects_Should_Generate_Same_Guids() 
    { 
     var obj = new object(); 
     var obj2 = obj; 

     var guid1 = ConsistentGuid.Generate(obj); 
     var guid2 = ConsistentGuid.Generate(obj2); 

     Assert.True(ReferenceEquals(obj, obj2)); 
     Assert.Equal(guid1, guid2); 
    } 

    [Fact] 
    public void ValueObjects_Of_DifferentTypes_Should_Generate_Different_Guids() 
    { 
     var obj = new object(); 
     var other = new int(); 

     var guid1 = ConsistentGuid.Generate(obj); 
     var guid2 = ConsistentGuid.Generate(other); 

     Assert.NotEqual(guid1, guid2); 
    } 

    [Fact] 
    public void ValueObjects_With_Same_Values_Should_Generate_Same_Guids() 
    { 
     var obj = 123; 
     var other = 123; 

     var guid1 = ConsistentGuid.Generate(obj); 
     var guid2 = ConsistentGuid.Generate(other); 

     Assert.False(ReferenceEquals(obj, other)); 
     Assert.Equal(guid1, guid2); 
    } 

    [Fact] 
    public void ValueObjects_With_Different_Values_Should_Generate_Different_Guids() 
    { 
     var obj = 123; 
     var other = 124; 

     var guid1 = ConsistentGuid.Generate(obj); 
     var guid2 = ConsistentGuid.Generate(other); 

     Assert.NotEqual(guid1, guid2); 
    } 

    class AReferenceType 
    { 
     public int SomeProperty { get; set; } 
     public string SomeOtherProperty { get; set; } 

     public AReferenceType(int a, string b) 
     { 
      SomeProperty = a; 
      SomeOtherProperty = b; 
     } 

     public override int GetHashCode() 
     { 
      return ConsistentGuid.Hash(new object[] 
      { 
       SomeProperty, 
       SomeOtherProperty 
      }); 
     } 
    } 

    [Fact] 
    public void ReferenceObjects_With_Same_Values_Should_Generate_Same_Guids() 
    { 
     var a = 123; 
     var b = "asd"; 

     var obj = new AReferenceType(a, b); 
     var other = new AReferenceType(a, b); 

     var guid1 = ConsistentGuid.Generate(obj); 
     var guid2 = ConsistentGuid.Generate(other); 

     Assert.False(ReferenceEquals(obj, other)); 
     Assert.Equal(obj.GetHashCode(), other.GetHashCode()); 
     Assert.Equal(guid1, guid2); 
    } 

    [Fact] 
    public void ReferenceObjects_With_Different_Values_Should_Generate_Different_Guids() 
    { 
     var a = 123; 
     var b = "asd"; 

     var obj = new AReferenceType(a, b); 
     var other = new AReferenceType(a + 1, b); 

     var guid1 = ConsistentGuid.Generate(obj); 
     var guid2 = ConsistentGuid.Generate(other); 

     Assert.NotEqual(guid1, guid2); 
    } 
} 
関連する問題