我们的系统中有GUID作为标识符。由于很容易弄乱一个实体的ID并将其传递到需要另一个实体的ID的方法中(假设您误将OrderId传递给InvoiceId,因为它们都是Guid
),所以我们创建了自己的类型对于Guid,编译器可以轻松地告诉我“嘿,不要在这里传递OrderId,我希望输入InvoiceId”。
因此,基本上,我们在Guid周围有很多包装纸。这些包装程序运行良好,它们基本上是Guid接口的副本,将所有工作委托给其内部存储的Guid。
我不知道的一件事是,我们两个自定义标识符上的Assert.AreEqual(a, b)
将失败。它会调用object.Equals(a, b)
,然后依次调用a == b
,并且不会调用我的operator ==
,而是会调用其他内容并返回false。但是,它不适用于Guid
,而且我无法弄清错过的地方。
要使我的自定义类型能够实际工作并在true
上返回object.Equals(a, b)
,并且已经在operator ==
上返回,我需要实现什么?
namespace ConsoleApp13
{
using System;
using System.Runtime.InteropServices;
//// Same signature, interfaces and and attributes as
//// https://referencesource.microsoft.com/#mscorlib/system/guid.cs
[StructLayout(LayoutKind.Sequential)]
[Serializable]
[ComVisible(true)]
// not accessible for me: [System.Runtime.Versioning.NonVersionable]
public struct CustomId : IFormattable, IComparable, IComparable<CustomId>, IEquatable<CustomId>
{
public static readonly CustomId Empty = new CustomId();
private readonly Guid internalGuid;
private CustomId(Guid guid)
{
this.internalGuid = guid;
}
public static bool operator ==(CustomId a, CustomId b)
{
return a.internalGuid == b.internalGuid;
}
public static bool operator !=(CustomId a, CustomId b)
{
return !(a.internalGuid == b.internalGuid);
}
public static CustomId NewGuid()
{
return new CustomId(Guid.NewGuid());
}
public static implicit operator Guid(CustomId value)
{
return value.internalGuid;
}
public static explicit operator CustomId(Guid value)
{
return new CustomId(value);
}
public override string ToString()
{
return "[" + this.GetType().Name + ":" + this.internalGuid.ToString("D") + "]";
}
public override int GetHashCode()
{
return this.internalGuid.GetHashCode();
}
public override bool Equals(object obj)
{
return this.internalGuid.Equals(obj);
}
public bool Equals(CustomId other)
{
return this.internalGuid.Equals(other.internalGuid);
}
public int CompareTo(object obj)
{
return this.internalGuid.CompareTo(obj);
}
public int CompareTo(CustomId other)
{
return this.internalGuid.CompareTo(other.internalGuid);
}
public string ToString(string format, IFormatProvider formatProvider)
{
return this.internalGuid.ToString(format, formatProvider);
}
}
internal static class Program
{
internal static void Main()
{
{
var a = CustomId.NewGuid();
var b = a;
// shows true false
Console.WriteLine("{0} {1}", a == b, object.Equals(a, b));
}
{
var a = Guid.NewGuid();
var b = a;
// shows true true
Console.WriteLine("{0} {1}", a == b, object.Equals(a, b));
}
Console.WriteLine(@"Done.");
Console.ReadLine();
}
}
}
答案 0 :(得分:3)
您的代码在这里:
public override bool Equals(object obj)
{
return this.internalGuid.Equals(obj);
}
会自动打开 ,但不会打开 other 实例,因此:如果obj
是{{1 }},因为CustomId
不会被交给Guid
(它需要CustomId
)。也许应该是:
Guid
请注意, public bool Equals(object obj) => obj is CustomId cid && cid == this;
应该相似:
CompareTo
答案 1 :(得分:1)
马克·格雷韦尔(Marc Gravell)的回答是正确的,但我想指出一点。
它调用object.Equals(a,b)依次调用a == b
这是一个错误的假设。如果object.Equals(a, b)
都不为空,则会调用a.Equals(b)
。细微的差异,但是差异:
https://referencesource.microsoft.com/#mscorlib/system/object.cs,d9262ceecc1719ab
public static bool Equals(Object objA, Object objB)
{
if (objA==objB) {
return true;
}
if (objA==null || objB==null) {
return false;
}
return objA.Equals(objB);
}