提问人:Pavel Kalandra 提问时间:8/21/2023 最后编辑:Pavel Kalandra 更新时间:8/21/2023 访问量:94
IEquatable<string>不适用于静态 Equals 方法
IEquatable<string> doesn't work with static Equals method
问:
我实现了一个名为 NonEmptyString 的类,当它不为空时不允许创建。我让这个类实现了 和 .我有 、 、 和 的覆盖。然后我写了一些测试,发现几乎所有东西都有效。除了 1 种情况,即调用静态 Equals 方法时,字符串参数是第一个参数。请在此处查看此行。IEquatable<NonEmptyString>
IEquatable<string>
Equals(object obj)
Equals(NonEmptyString other)
Equals(string other)
GetHashCode()
string text = "ASDF123";
NonEmptyString nonEmptyString = NonEmptyString.CreateUnsafe("ASDF123");
Assert.True(text == nonEmptyString);
Assert.True(nonEmptyString == text);
Assert.True(text.Equals(nonEmptyString)); // This one returns true as expected.
Assert.True(nonEmptyString.Equals(text));
Assert.True(Equals(text, nonEmptyString)); //This is the only one that doesn't work.
Assert.True(Equals(nonEmptyString, text));
我想知道为什么会这样 - 当我查看对象上 Equals 方法的实现时,它确实调用了虚拟方法。因此,如果该方法返回 false,那么我希望同样的事情应该发生 - 但那个有效。这是我进入调用时看到的静态 Equals 的实现。Equals(object obj)
text.Equals(nonEmptyString)
public static bool Equals(object? objA, object? objB)
{
if (objA == objB)
{
return true;
}
if (objA == null || objB == null)
{
return false;
}
return objA.Equals(objB);
}
我什至尝试以这种方式覆盖运算符以将字符串与 NonEmptyString 进行比较(我真的没想到这会有所帮助,但值得一试)==
public static bool operator ==(string obj1, NonEmptyString obj2)
public static bool operator !=(string obj1, NonEmptyString obj2)
public static bool operator ==(NonEmptyString obj1, string obj2)
public static bool operator !=(NonEmptyString obj1, string obj2)
我能做些什么来完成这项工作吗? 预计这不应该起作用吗? 这是 .NET 中的错误吗?
这是核心实现(我从中删除了不重要的部分。
public sealed class NonEmptyString : IEquatable<string>, IEquatable<NonEmptyString>
{
private NonEmptyString(string value)
{
Value = value;
}
public string Value { get; }
public static NonEmptyString CreateUnsafe(string value)
{
if (string.IsNullOrWhiteSpace(value))
{
throw new ArgumentException("You cannot create NonEmptyString from whitespace, empty string or null.");
}
return new NonEmptyString(value);
}
public override int GetHashCode()
{
return Value.GetHashCode();
}
public override bool Equals(object obj)
{
return ReferenceEquals(this, obj) ||
obj is NonEmptyString otherNonEmpty && Equals(otherNonEmpty) ||
obj is string otherString && Equals(otherString);
}
public bool Equals(string other)
{
return Value.Equals(other);
}
public bool Equals(NonEmptyString other)
{
return Value.Equals(other?.Value);
}
public override string ToString()
{
return Value;
}
}
答:
我认为这是因为与调用相同,不能被覆盖。即:它尝试使用默认方法将您的类对象与字符串进行比较,而不是您为访问其属性而定义的比较方法。Equals(object1, object2)
object1.ReferenceEquals(object2)
ReferenceEquals()
string
ReferenceEquals
Value
评论
objA.Equals(objB)
C# 中的 IEquatable 接口提供了一种比较相同类型的两个对象是否相等的方法。它通常用于重写自定义类的 Equals 方法。
但是,IEquatable 不适用于静态方法。这样做的原因是 IEquatable 需要以实例级方式实现 Equals 方法,这意味着它将当前对象与相同类型的另一个对象进行比较。Equals
另一方面,静态 Equals 方法不绑定到类的特定实例,并且可以比较不同类型的对象。它通常在更通用的意义上用于检查两个对象之间的是否相等。
若要使 IEquatable 正常工作,需要在实现接口的类中的实例级别实现 Equals 方法。例如:
public class MyClass : IEquatable<MyClass>
{
public string Property { get; set; }
public bool Equals(MyClass other)
{
if (other == null)
return false;
return Property == other.Property;
}
public override bool Equals(object obj)
{
if (obj == null || !(obj is MyClass))
return false;
return Equals((MyClass)obj);
}
public override int GetHashCode()
{
return Property.GetHashCode();
}
}
然后,可以使用 IEquatable 接口通过 Equals 方法比较 MyClass 的实例:
MyClass obj1 = new MyClass { Property = "Test" };
MyClass obj2 = new MyClass { Property = "Test" };
bool areEqual = obj1.Equals(obj2); // true
请注意,在上面的示例中,静态方法不参与相等性比较。Equals
评论
您似乎遇到的问题是当您从 或 类调用重载时。Equals
string
object
请看这段代码:
string text = "ASDF123";
NonEmptyString nonEmptyString = NonEmptyString.CreateUnsafe(text);
/* 3 */ Assert.True(text.Equals(nonEmptyString));
/* 5 */ Assert.True(Equals(text, nonEmptyString));
在第 3 行,对的调用是在不知道您的类的实例上 - 因此,无论 的基础值是否相等,它都会始终返回。Equals
string
NonEmptyString
false
NonEmptyString
在第 5 行,对的调用是在实例上,该实例同样不知道您的类 - 因此,无论 的基础值是否相等,它都将始终返回。Equals
object
NonEmptyString
false
NonEmptyString
下面是代码的编译器优化版本:
NonEmptyString nonEmptyString = NonEmptyString.CreateUnsafe("ASDF123");
Assert.True("ASDF123".Equals(nonEmptyString));
Assert.True(object.Equals("ASDF123", nonEmptyString));
您无法控制这些重载。Equals
为了让你的生活尽可能简单,你应该实现隐式和显式强制转换运算符,如下所示:==
public static bool operator ==(string obj1, NonEmptyString obj2) => obj2.Equals(obj1);
public static bool operator !=(string obj1, NonEmptyString obj2) => !obj2.Equals(obj1);
public static bool operator ==(NonEmptyString obj1, string obj2) => obj1.Equals(obj2);
public static bool operator !=(NonEmptyString obj1, string obj2) => !obj1.Equals(obj2);
public static implicit operator string(NonEmptyString nes) => nes.Value;
public static explicit operator NonEmptyString(string text) => NonEmptyString.CreateUnsafe(text);
评论
text.Equals(NonEmptyString)
string.Equals
string
SpanHelpers.SequenceEqual(ref Unsafe.As<char, byte>(ref strA.GetRawStringData()), ref Unsafe.As<char, byte>(ref strB.GetRawStringData()), (UIntPtr)(uint)(strA.Length * 2))
object.Equals
==
string x = "a"; bool result = (((object)"ab") == ((object)(x + "b")));
False
上一个:随机选择 - 加权误差
下一个:为什么模板只能在头文件中实现?
评论