我从another question(稍加修改)借用了以下代码,以便在我的代码中使用:
internal class PositiveDouble
{
private double _value;
public PositiveDouble(double val)
{
if (val < 0)
throw new ArgumentOutOfRangeException("Value needs to be positive");
_value = val;
}
// This conversion is safe, we can make it implicit
public static implicit operator double(PositiveDouble d)
{
return d._value;
}
// This conversion is not always safe, so we're supposed to make it explicit
public static explicit operator PositiveDouble(double d)
{
return new PositiveDouble(d); // this constructor might throw exception
}
}
此代码的原作者正确地遵守MSDN implicit&amp;中提供的警告。 explicit文档,但这是我的问题: explicit
是否始终需要特殊代码?
所以,我的代码中有一些类型(例如“Volume”)派生自PositiveDouble,我希望能够像下面的第一行一样方便地设置实例:
Volume v = 10; //only allowed by implicit conversion
Volume v = new Volume(10) //required by explicit conversion, but gets messy quick
强制在任何地方使用显式强制转换都会使代码的可读性降低。它如何保护用户?在我的程序的语义中,我从不期望卷是负面的;事实上,如果它发生了,我希望抛出异常。因此,如果我使用隐式转换并抛出,“意外结果”可能会破坏我吗?
答案 0 :(得分:14)
C#语言规范在10.10.3转换运算符下说:
如果用户定义的转换可能引起异常(例如,因为源参数超出范围)或信息丢失(例如丢弃高位),那么转换应该被定义为显式转换。
此外,来自MSDN: implicit (C# Reference):
一般情况下,隐式转换运算符不应该抛出异常并且永远不会丢失信息,以便在没有程序员意识的情况下可以安全地使用它们。如果转换运算符不符合这些条件,则应标记为显式。
考虑到这一点,您的operator PositiveDouble(double d)
不应标记为implicit
,因为Volume v = -1
会引发异常。
所以回答你的问题:
在潜在的特殊代码中是否总是需要显式?
不,没有必要,但应该。
接近基于意见:如果您的代码是使用此转换的唯一代码,并且您发现隐式转换更易于阅读和/或维护,请随意使用。
至于
它如何保护用户?
请参阅MSDN: explicit (C# Reference)提及:
如果转换操作可能导致异常或丢失信息,则应将其标记为显式。这可以防止编译器以可能无法预料的后果静默调用转换操作。
当发生这种情况时,我无法理解,但是,如果你认为你的代码中的任何地方都没有从负双重转换,那么这不应该抛出。
答案 1 :(得分:13)
转换只有在始终成功时才应隐含。如果它们可能失败或导致信息丢失,它们应该是明确的,因为这需要转换操作的调用者故意表明他们想要这种转换,因此准备处理结果,无论可能是什么。
我们可以在框架中看到这个原始数值类型;将int
分配给long
是一种隐式转换,因为它始终会以预期结果成功。另一种方式可能导致检查上下文中出现OverflowException
,并且可能导致在未经检查的上下文中截断(丢失信息),因此您需要通过显式转换来表明您打算进行此转换。