我正在制作一个自定义字符串类。 (主要是为了自我启发的目的 - 我知道我不会提出比常规string
类更好的东西,我不能用扩展方法轻松做到。)我遇到了在单元测试中测试相等性的奇怪问题。它几乎在所有方面都有效,除了一个。这是单元测试:
MyString myStr = "MyNewString";
Assert.AreEqual("MyNewString", myStr); //Fails
Assert.AreEqual(myStr, "MyNewString");
Assert.IsTrue(myStr.Equals("MyNewString"));
Assert.IsTrue(("MyNewString").Equals(myStr));
Assert.IsTrue(myStr == "MyNewString");
Assert.IsTrue("MyNewString" == myStr);
string realString = "MyNewString";
Assert.AreEqual(realString, myStr); //Fails
Assert.AreEqual(myStr, realString);
Assert.IsTrue(myStr.Equals(realString));
Assert.IsTrue(realString.Equals(myStr));
Assert.IsTrue(myStr == realString);
Assert.IsTrue(realString == myStr);
在失败的两种情况下,如果我在.ToString()
之后添加myStr
,则会成功,但在任何其他情况下都不需要这样做。我猜它是因为string
的{{1}}方法不了解我的课程,即使我已经设置了隐式转换。该课程的相关部分如下:
Equals
public struct MyString : ICloneable, IComparable<MyString>, IComparable<string>,
IEnumerable<char>, IEquatable<MyString>, IEquatable<string>
{
private char[] text;
//Constructors
...
public static implicit operator MyString(string s)
{
return s == null ? null : new MyString(s);
}
public static implicit operator string(MyString s) { return s.ToString(); }
public static bool operator ==(MyString a, MyString b) { return a.Equals(b); }
public static bool operator !=(MyString a, MyString b) { return !(a.Equals(b)); }
public static bool operator ==(MyString a, string b) { return a.Equals(b); }
public static bool operator !=(MyString a, string b) { return !(a.Equals(b)); }
public static bool operator ==(string a, MyString b) { return b.Equals(a); }
public static bool operator !=(string a, MyString b) { return !(b.Equals(a)); }
public override string ToString() { return new string(text); }
public override bool Equals(object obj)
{
if (obj == null)
return false;
if (base.Equals(obj))
return true;
if (obj is MyString)
return this.Equals((MyString)obj);
if (obj is string)
return this.Equals((string)obj);
return false;
}
public bool Equals(MyString other) { return this.CompareTo(other) == 0; }
public bool Equals(string other) { return this.CompareTo(other) == 0; }
}
和常规CompareTo()
也有MyString
,但请相信我他们的工作。我还能做些什么来使这个平等测试工作吗?它似乎适用于所有其他情况,但这一个。我不确定string
内部是如何实际操作的,但是如果测试相等性的其他方法都有效,为什么这个方法会失败呢?
编辑:添加我的GetHashCode(),因为它可能是相关的:
Assert.AreEqual
当然这可能与public override int GetHashCode()
{
int hash = 0;
for (int i = 0; i < Length; i++ )
hash ^= (i * this[i]);
return hash;
}
不匹配,但我无法知道,因为我看不到他们的代码。 (我可以看到元数据,但它只包含标题而不是实现。)尝试用string.GetHashCode()
的快捷方式替换它:
string.GetHashCode()
仍然无效。还尝试添加扩展方法:
public override int GetHashCode()
{
return new string(text).GetHashCode();
}
这也不起作用。还有其他想法吗?
答案 0 :(得分:0)
调用堆栈提到Assert.AreEqual(object, object)
的调用
我假设这会调用不会调用任何运算符的object.Equals(object, object)
。见http://blogs.msdn.com/b/csharpfaq/archive/2004/03/29/when-should-i-use-and-when-should-i-use-equals.aspx
顺便说一句:请务必覆盖GetHashCode()
我不得不稍稍延伸一下。
Assert.AreEqual(a,b)
调用object.Equals(a,b)
来调用a.equals(b)
。所以你的测试会调用string.Equals(b)
。
string.Equals
的实现对ReferenceEqualsComparism的String进行了隐式转换。因此,只要不存在对字符串的隐式强制转换,string.equality()就会失败。
简而言之:从MyString到string的隐式转换不起作用=&gt;见In c# 3.0, is it possible to add implicit operators to the string class?
var myStr = "hello" as MyString; // does call implicit cast to MyString
var y = myStr as string; // does not call implicit cast to String becaus you are not owner of string