私はこの答えにハッシングアルゴリズムを使ってこれを考え出しました。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);
}
}
私はなぜあなたが 'Guid'を使いたいのか分かりません。 –
言い換えれば、なぜこのために 'Guid'を使うのですか? –