com*_*cme 7 c# struct unit-testing implicit-conversion
我创建了一个自定义结构来表示金额.它基本上是一个包装器decimal.它有一个隐式转换运算符将其强制转换为decimal.
在我的单元测试中,我断言Amount等于原始十进制值,但测试失败.
[TestMethod]
public void AmountAndDecimal_AreEqual()
{
Amount amount = 1.5M;
Assert.AreEqual(1.5M, amount);
}
Run Code Online (Sandbox Code Playgroud)
当我使用int(我没有创建转换运算符)时,测试确实成功.
[TestMethod]
public void AmountAndInt_AreEqual()
{
Amount amount = 1;
Assert.AreEqual(1, amount);
}
Run Code Online (Sandbox Code Playgroud)
当我悬停时AreEqual,它显示第一个解析为
public static void AreEqual(object expected, object actual);
Run Code Online (Sandbox Code Playgroud)
而第二个导致
public static void AreEqual<T>(T expected, T actual);
Run Code Online (Sandbox Code Playgroud)
看起来这个int值1是隐式地转换为a Amount,而decimal值1.5M则不是.
我不明白为什么会这样.我本来希望恰恰相反.第一次单元测试应该能够投射decimal到Amount.
当我添加隐式强制转换int(没有意义)时,第二个单元测试也会失败.因此,添加隐式强制转换运算符会破坏单元测试.
我有两个问题:
Amount结构,以便两个测试都能成功?(我知道我可以改变测试来做一个明确的转换,但如果我不是绝对必须,我不会)
我的Amount结构(只是一个显示问题的最小实现)
public struct Amount
{
private readonly decimal _value;
private Amount(decimal value)
{
_value = value;
}
public static implicit operator Amount(decimal value)
{
return new Amount(value);
}
public static implicit operator decimal(Amount amount)
{
return amount._value;
}
}
Run Code Online (Sandbox Code Playgroud)
当你可以implicit在两个方向转换时发生不好的事情,这是一个例子.
由于隐式转换,编译器能够选择Assert.AreEqual<decimal>(1.5M, amount);并Assert.AreEqual<Amount>(1.5M, amount);具有相同的值.*
由于它们是相同的,所以推理都不会引起过载.
由于推理没有超载,因此无法将其列入选择最佳匹配的列表中,只有(object, object)表单可用.所以这是挑选的.
随着Assert.AreEqual(1, amount)然后因为是从隐式转换int到Amount(通过隐含的内部- >十进制),但没有从隐式转换Amount到int编译器认为"很明显,他们的意思是Assert.AreEqual<Amount>()在这里"†,并因此被采摘.
你可以明确地挑过载使用Assert.AreEqual<Amount>()或Assert.AreEqual<decimal>(),但你可能会更好过让你转换的"缩小"从有到是一个explicit,如果在所有可能的,因为你的结构的这一特征会伤害你.(华友世纪为单位测试发现缺陷).
*另一个有效的重载选择是选择Assert.AreEqual<object>,但它永远不会被推理选择,因为:
object无论如何,它总是被非泛型形式打败.因此,只能通过<object>在代码中包含它来调用它.
†编译器将对其说的所有内容都视为含义明显或完全不可理解.有人也喜欢这样.
| 归档时间: |
|
| 查看次数: |
502 次 |
| 最近记录: |