7

一个例子是:

XNamespace ns = "my namespace"

为什么不?:

XNamespace ns = new XNamespace ( "my namespace" )

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

有这方面的指导方针吗?

4

5 回答 5

10

方便?

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

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

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

有这方面的指导方针吗?

提供尽可能少的隐式转换,因为它们可能隐藏问题。隐式转换减少显式性的程度与它们增加简洁性的程度相同。有时这很好,但有时不是。

我发现最好将隐式转换限制为非常相似的类型,例如上面示例中的类似数字的对象:int本质上是 is-a Complex(从数学的角度来看;即使它不是通过继承建模的),因此隐式转换使感觉。

在 VB 中,隐式转换称为“<code>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);
    }
}

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

于 2010-09-28T18:04:57.187 回答
5

我相信,对 XName 等简单类型使用隐式转换的原因之一是调用方法的便利性。

例如,你可以写

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

提取数据的简单性是 LINQ 的全部意义所在,如果我们必须编写

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

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

这里的另一个重要问题是 XName 是原子化的。见MSDN

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

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

您不能在构造函数中提供原子化,但定义转换允许您从池中选择相应的对象并将其返回,就好像它是一个新实例一样。

于 2010-09-28T18:11:10.593 回答
3

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

问题之一是隐式/显式转换的使用进一步重载了强制转换运算符的函数。它赋予了它双重目的

  • 通过对象层次结构中的不同类型/接口查看同一个对象
  • 将对象完全覆盖为新类型

不幸的是,C# 已经在其他领域做了后者(使用原语和装箱)。

于 2010-09-28T18:05:09.523 回答
2

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

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

于 2010-09-28T18:09:58.460 回答
1

就个人而言,当我知道 rhs 可以转换为类的静态成员时(比如说color = "red"to imply color = Colors.Red) ,我会使用转换

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

于 2010-09-28T18:05:47.503 回答