我想接受任何对象并获得代表该对象的guid。
我知道这需要很多东西。我正在为常见的应用程序寻找一个足够好的解决方案。
我的具体用例是缓存,我想知道用于创建我正在缓存的东西的对象已经在过去做过了。将有2种不同类型的对象。每种类型仅包含公共属性,并且可能包含列表/ ienumable。
假设对象可以序列化我的第一个想法是将它序列化为json(通过原生jsonserlizer或newtonsoft),然后获取json字符串并将其转换为uuid版本5,详见详见How can I generate a GUID for a string?
我的第二种方法,如果它不可序列化(例如包含字典)将使用公共属性上的反射来生成某种类型的唯一字符串,然后将其转换为uuid版本5.
这两种方法都使用uuid版本5将字符串带到guid。是否有一个经过验证的c#类可以生成有效的uuid 5指南?要点看起来很好,但想要确定。
我正在考虑使c#名称空间和类型名称成为uuid 5的名称空间。这是名称空间的有效使用吗?
我的第一种方法对于我的简单用例来说足够好,但我想探索第二种方法,因为它更灵活。
如果创建guid无法保证合理的唯一性,则应该抛出错误。当然,超级复杂的物体会失败。如果使用反射,我怎么知道这种情况?
我正在寻找第二种方法的新方法或关注/实施。
答案 0 :(得分:0)
正如评论中所说,这里并没有完全用白银制造的子弹,但是有一些子弹非常接近。使用哪一个取决于您要与您的类一起使用的类型以及您的上下文,例如您何时认为两个对象相等。但是,请注意,您将始终面临可能的冲突,一个GUID不足以保证避免冲突。您所要做的就是减少发生碰撞的可能性。
就您而言,
已经过去了
听起来像您不想引用引用相等,但想要使用值相等的概念。最简单的方法是信任类使用值相等来实现相等,因为在这种情况下,您已经使用GetHashCode
完成了操作,但是冲突发生的可能性更高,因为它只有32位。此外,您会假设编写班级的人做得很好,但这并不总是一个好的假设,特别是因为人们倾向于先怪您而不是自己。
否则,您最好的机会是将序列化与您选择的哈希算法结合使用。我会推荐MD5,因为它是最快的,可以产生GUID所需的128位。如果您说您的类型仅包含公共属性,那么我建议像这样使用XmlSerializer
:
private MD5 _md5 = new MD5CryptoServiceProvider();
private Dictionary<Type, XmlSerializer> _serializers = new Dictionary<Type, XmlSerializer>();
public Guid CreateID(object obj)
{
if (obj == null) return Guid.Empty;
var type = obj.GetType();
if (!_serializers.TryGetValue(type, out var serializer))
{
serializer = new XmlSerializer(type);
_serializers.Add(type, serializer);
}
using (var stream = new MemoryStream())
{
serializer.Serialize(stream, obj);
stream.Position = 0;
return new Guid(_md5.ComputeHash(stream));
}
}
几乎所有串行器都有其缺点。 XmlSerializer
无法序列化循环对象图,DataContractSerializer
要求您的类型具有专用属性,并且基于SerializableAttribute
的旧序列化程序也需要设置该属性。您必须以某种方式做出假设。
答案 1 :(得分:0)
平等问题是一个难题。
这里有一些关于如何解决问题的想法。
散列序列化的对象
一种方法是序列化一个对象,然后按照Georg的建议对结果进行哈希处理。
使用md5校验和可通过正确的输入为您提供强大的校验和。
但是正确是问题所在。
您可能无法使用通用的序列化框架,因为:
这就是为什么,您应该仔细测试所做的任何序列化。
否则,您可能会得到对象的假阳性/假阳性(大多是假阴性)。
需要考虑的几点:
由您使用现有的序列化器还是自己决定。
自己执行此操作比较容易出错,但是您可以完全控制相等性和序列化的各个方面。
使用现有的串行器也容易出错,因为您需要测试或证明结果是否始终如您所愿。
引入明确的顺序并使用树
如果您可以控制源代码,则可以引入自定义订单功能。
订单必须考虑所有属性,子对象,列表等。
然后,您可以创建一个二叉树,并使用该命令来插入和查找对象。
第一种方法提到的相同问题仍然适用,您需要确保这样检测到相等的值。 大的O性能也比使用散列更糟糕。但是在大多数实际的示例中,实际性能应该是可比的或至少足够快。
好处是,一旦发现不相等的属性或值,就可以停止比较两个对象。因此,无需始终关注整个对象。 一棵二叉树需要进行O(log2(n))比较才能查找,因此相当快。
不好的是,您需要访问所有实际对象,从而将它们保存在内存中。 哈希表只需要进行O(1)比较即可查找,因此(理论上至少)会更快。
将它们放入数据库
如果将所有对象存储在数据库中,则数据库可以为您进行查找。
数据库在比较对象方面非常出色,并且内置了处理等价/接近等价问题的机制。
我不是数据库专家,因此对于此选项,其他人可能会对此解决方案的性能有更深入的了解。
答案 2 :(得分:-1)
正如其他人在评论中所说的那样,如果你愿意以GetHashCode
作为你的关键,那么int
可能会为你提供帮助。如果没有,则有一个Guid
构造函数,其长度为byte[]
。您可以尝试以下内容
using System.Linq;
class Foo
{
public int A { get; set; }
public char B { get; set; }
public string C { get; set; }
public Guid GetGuid()
{
byte[] aBytes = BitConverter.GetBytes(A);
byte[] bBytes = BitConverter.GetBytes(B);
byte[] cBytes = BitConverter.GetBytes(C);
byte[] padding = new byte[16];
byte[] allBytes =
aBytes
.Concat(bBytes)
.Concat(cBytes)
.Concat(padding)
.Take(16)
.ToArray();
return new Guid(allBytes);
}
}