使用隐式/显式转换而不是构造函数的原因是什么?

时间:2010-09-28 18:02:33

标签: c# .net constructor type-conversion base-class-library

一个例子是:

XNamespace ns = "my namespace"

为什么不呢?:

XNamespace ns = new XNamespace ( "my namespace" )

使用隐式/显式转换而不是构造函数背后的想法是什么?方便?

这是否有指导原则?

5 个答案:

答案 0 :(得分:9)

  

便利?

或多或少,是的。考虑一下你有一个类似数字的对象(例如,Complex)进行计算的情况。显然,编写代码如:

Complex result = c1 * new Complex(2) + new Complex(32);

非常烦人且难以阅读。隐式转换在这里有帮助(在这个示例中,替代方法是运算符重载,但这会导致大量类似的重载)。

  

这是否有指导原则?

提供尽可能少的隐式转换,因为它们可能会隐藏问题。隐式转换将显式性降低了相同的量,从而增加了简洁性。有时这很好,但有时候不是。

我发现最好将隐式转换限制为非常类似的类型,例如上例中的类似数字的对象:int本质上是一个Complex (从数学的角度来看;即使它没有通过继承建模),因此隐式转换是有道理的。

在VB中,隐式转换称为“Widening”(而不是Narrowing,即explicit),这很好地描述了:在此过程中没有丢失任何信息转换。

此外,运算符本质上是一个构建器函数,并且具有构造函数的构建函数的(通常)优点:即,它可以重用缓存的值而不是始终创建新的实例。

考虑我的Complex示例。我们可能希望缓存常用复数的值:

Class Complex {
    // Rest of implementation.

    private static Complex[] cache = new[] {
        new Complex(-1), new Complex(0), new Complex(1) };

    public implicit operator Complex(int value) {
        if (value >= -1 && value <= 1)
            return cache[value];
        else
            return new Complex(value);
    }
}

当然,这种微观优化是否有效是另一个问题。

答案 1 :(得分:5)

我认为,使用XName等简单类型进行隐式转换的原因之一是调用方法的便利性。

例如,你可以写

var info = root.Elements ("user").Element ("info").Value;

提取数据的简单性就是LINQ的全部内容,如果我们必须编写

var info = root.Elements (new XName ("user")).Element (new XName ("info")).Value;

即使对于最简单的查询,LINQ对于复杂的查询是否完全值得?

这里的另一个重要问题是XNames是雾化的。 见MSDN

  

保证XName对象被雾化;也就是说,如果两个XName对象具有完全相同的命名空间和完全相同的本地名称,它们将共享同一个实例。为此目的,还明确提供了相等和比较运算符。

     

除了其他好处之外,此功能还允许更快地执行查询。过滤元素或属性的名称时,谓词中表示的比较使用身份比较,而不是值比较。确定两个引用实际引用同一个对象比比较两个字符串要快得多。

您无法在构造函数中提供雾化,但定义转换允许您从池中选择相应的对象并将其作为新实例返回。

答案 2 :(得分:3)

隐式/显式转换的使用是方便性问题,许多编程指南建议您避免使用显式ConvertToXXX方法。

其中一个问题是使用隐式/显式转换会进一步重载转换运算符的功能。它赋予它

的双重目的
  • 通过对象层次结构中的不同类型/界面查看同一对象
  • 将对象完全转换为新类型

不幸的是,C#已经在其他领域(使用原语和拳击)执行后者。

答案 3 :(得分:2)

如果两个类应该可以相互转换,但它们不共享自动允许此行为的基类接口,则可以使用转换。隐式转换应永远不会存在数据丢失的可能性;它们通常被视为“扩大”转化。例如,将int转换为long是一种扩大的转换,并且隐含的转换没有固有的问题。明确的转换可能涉及数据丢失的可能性; long可能会或可能不会转换为int,具体取决于其值。

我使用隐式转换的一个技巧是在我没有其他合理选项时将不同命名空间中的类转换为彼此。例如,一个WCF服务返回一个AuthenticationToken对象,我需要将该对象传递给另一个名称空间中的WCF服务。两者都有这个AuthenticationToken对象,并且常量转换会很痛苦。我的解决方案涉及在部分类中使用public static implicit operator来添加转换每种方式的功能。

答案 4 :(得分:1)

就个人而言,当我知道rhs可能被转换为类的静态成员时(例如说color = "red"暗示color = Colors.Red

,我会使用转换

当我打算实际创建一个新实例时,我使用new运算符。