什么时候应该使用C#的隐式类型转换运算符?


14

在C#中,我们可以像这样重载隐式转换运算符(来自MSDN的示例):

struct Digit
{
    /* ... */
    public static implicit operator byte(Digit d)  // implicit digit to byte conversion operator
    {
        /* ... */
    }
}

因此,我们可以拥有一个类型,一个自定义值类型,将自己神奇地转换为另一种(不相关的)类型,从而使观众感到困惑(直到他们凝视到后台并看到隐式转换操作符为止)。

我不喜欢让任何阅读我的代码的人迷惑不解。我认为没有很多人这样做。

问题是,隐式类型转换运算符的用例是什么,它们不会使我的代码更难理解?


1
哇。我实际上不知道这是存在的。并不是说它一定是一件好事。我知道人们真的很讨厌C ++中的这种功能隐藏。
Katana314,2015年

@ Katana314:这不是人们所讨厌的,而是关于有人添加了具有令人惊讶的行为(最好是微妙的惊奇)的重载(无论是运算符,转换函数,构造函数,自由函数还是成员函数)。
Deduplicator 2015年

我建议您阅读C ++中的“运算符重载”,特别是“广播”运算符。我怀疑关于/反对的许多相同论点都是相同的,除了辩论已经进行了三遍,只要存在C#,还有很多东西需要阅读。

Answers:


18

我只建议在类型之间进行隐式转换,这些类型以不同的方式大致代表相同的值。例如:

  • 不同的颜色种类一样RGBHSLHSVCMYK
  • 相同物理量(Metervs Inch)的不同单位。
  • 不同的坐标系(极坐标系和笛卡尔坐标系)。

但是,有一些强有力的准则可以指示何时适合定义隐式转换:

  • 如果转换导致精度或范围的重大损失,则不应隐式转换(例如:从float64到float32或从long到int)。
  • 如果该转换可以引发(InvalidCast)异常,则该转换不应是隐式的。
  • 如果转换每次执行都会导致堆分配,则不应隐式进行。
  • 如果转换不是O(1)操作,则不应隐式进行。
  • 如果源类型或目标类型是可变的,则转换不应是隐式的。
  • 如果转换依赖于某种上下文(数据库,区域性设置,配置,文件系统等),则它不应是隐式的(在这种情况下,我也不建议使用显式转换运算符)。

现在说您的转换运算符f: T1 -> T2没有违反以上任何规则,那么以下行为强烈表明转换可以隐式进行:

  • 如果那样的a == bf(a) == f(b)
  • 如果那样的a != bf(a) != f(b)
  • 如果那样的a.ToString() == b.ToString()f(a).ToString() == f(b).ToString()
  • 等用于在T1和上定义的其他操作T2

您所有的示例都可能有损。无论它们是否足够精确,……
Deduplicator 2015年

是的,我意识到:-)。我想不出一个更好的术语“有损”。我所说的“有损”是指范围或精度大大降低的转化。例如从float64到float32或从long到int。
Elian Ebbing 2015年

我认为!= b => f(a)!= f(b),可能不适用。例如,在数学方面,有很多函数可能针对不同的输入,floor()和ceil()返回相同的值
cdkMoose

@cdkMoose您当然是正确的,这就是为什么我更多地将这些属性视为“奖励点”而不是规则的原因。第二个属性仅表示转换函数是内射的。当您转换为具有严格更大范围的类型(例如,从int32到int64)时,通常会出现这种情况。
Elian Ebbing 2015年

@cdkMoose另一方面,第一个属性只是声明的相同等价类中的两个值T1(由表示为==on T1)始终映射到的相同等价类中的两个值T2。现在考虑了一下,我想隐式转换实际上应该需要第一个属性。
Elian Ebbing 2015年

6

问题是,隐式类型转换运算符的用例是什么,它们不会使我的代码更难理解?

当类型无关系(程序员)。在少数情况下,您有两种不相关的类型(就代码而言),而这两种类型实际上是相关的(就领域或合理的程序员而言)。

例如,一些代码可以进行字符串匹配。常见的情况是匹配字符串文字。而不是调用IsMatch(input, new Literal("some string")),隐式转换使您摆脱了仪式(代码中的噪音),而专注于字符串文字。

大多数程序员都会看到IsMatch(input, "some string")并迅速了解发生了什么。它使您在呼叫站点上的代码更加清晰。总之,这使得它有点更容易理解什么是怎么回事,在轻微的费用怎么说是怎么回事。

现在,您可能会争辩说,执行相同操作的简单函数重载会更好。是的。但是,如果这种事情无处不在,那么进行一次转换比进行一堆函数重载更干净(代码更少,一致性更高)。

您可能会争辩说,最好要求程序员显式创建中间类型,以便他们看到“实际情况”。那不是那么简单。就个人而言,我认为文字字符串匹配例子是关于“什么是怎么回事”非常明确-程序员需要知道的机制是如何发生的一切。您知道所有代码如何由运行代码的各种处理器执行吗?总是有抽象的线,其中程序员不再在乎关于如何东西工程。如果您认为隐式转换步骤很重要,请不要使用隐式转换。如果您认为他们只是为了让计算机开心而举行的典礼,那么程序员最好不要在任何地方都看到这种噪音,


您的最后一点可以而且应该更进一步:还有一条界限,程序员最好不要理会某些事情的完成,因为这与合同无关。
Deduplicator 2015年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.