什么是关于何时,应该或不应该定义用户定义的隐式转换的一般指导原则?
我的意思是,例如,“隐式转换永远不会丢失信息”,“隐式转换永远不应该抛出异常”,或“隐式转换永远不应该实例化新对象”。我很确定第一个是正确的,第三个不是(或者我们只能隐式转换为结构),而我不知道第二个。
答案 0 :(得分:14)
第一个并不像你想象的那么简单。这是一个例子:
using System;
class Test
{
static void Main()
{
long firstLong = long.MaxValue - 2;
long secondLong = firstLong - 1;
double firstDouble = firstLong;
double secondDouble = secondLong;
// Prints False as expected
Console.WriteLine(firstLong == secondLong);
// Prints True!
Console.WriteLine(firstDouble == secondDouble);
}
}
我个人很少创建自己的隐式转换。我对框架中的那些人感到高兴,但我很少觉得添加自己的东西会让生活更美好。 (一般来说,值类型也是如此,顺便说一句。)
编辑:只是为了实际回答这个问题,可能值得阅读conversion operators part of the Microsoft class library design guidelines。
答案 1 :(得分:2)
我肯定同意第一个 - 第二个大部分时间(“从不说永远不会”),但不会被第三个感到兴奋;除了其他任何东西,它在结构和类之间产生了不必要的区别。在某些情况下,进行隐式转换可以大大简化调用约定。
对于显式转换,一切皆有可能。
但是,通常不需要编写转换运算符。在许多情况下,显式运算符更有用,并且如果条件不正确则接受它们可能会中断(例如,如果它们没有值,则使用Nullable<T>
。)
答案 2 :(得分:1)
如果你只支持你自己类型的对象之间的隐式转换,我建议你应该决定应该对这些转换应用什么“公理”(例如,如果a==b
可能会有所帮助。 ,b==c
和a==c
都是合法的,其中两个是真的,第三个也必须是真的)然后确定一组最有用的转换,这些转换会使这些公理成立。我在http://supercatnet.blogspot.com/2013/09/axioms-of-implicit-type-conversion.html的博客上讨论了四个有用的公理(不幸的是,.NET Framework包含违反所有四个的转换,但不允许转换,而不必转换。)
需要考虑的一个重要事项是隐式转换到不精确类型在大多数情况下会比来自不精确类型的转换带来更大的惊讶风险,但是有一个值得注意的例外:如果某个更精确类型的某些东西被输入到一个方法或操作符,该方法或操作符具有可以转换为更精确类型和更精确类型的重载,则某种程度的“惊人”行为将是几乎不可避免,除非人们无法进行隐式转换[例如程序员写if (someLong == someFloat)
时的行为可能会令人惊讶,但不是因为隐式long
到float
转换的精度损失是惊人的,而是因为至少有六种不同的方式可能想要比较long
和float
(*),以及任何,这意味着编译器可能会附加到直接比较中,这会使那些期望其他内容的人感到震惊。我知道避免这种惊讶的唯一解决方案是提供重载以明确涵盖所有不明确的情况并用[Obsolete()]
标记标记它们。这样做有点尴尬,但能提供能够满足所有四个公理的实质性优势。
(*)程序员可能打算测试长度是否等于浮动到最近的浮点值,向零截断,或向负无穷大浮动;或者,程序员可能想要测试float
是否代表long
,float
和long
是否具有相同的名义值,或者是否float
和long
都会转换为相同的double
。
答案 3 :(得分:0)
导致我提出这个问题的边缘情况违反了第二个问题。即,我有一个懒惰的&lt; T&gt;。 class(并不是每个人?)并开始思考我是否不应该向T提供隐式转换。我的直觉是肯定,当前版本确实如此,但我不太确定。