一个例子是:
XNamespace ns = "my namespace"
为什么不?:
XNamespace ns = new XNamespace ( "my namespace" )
使用隐式/显式转换而不是构造函数背后的想法是什么?方便?
有这方面的指导方针吗?
一个例子是:
XNamespace ns = "my namespace"
为什么不?:
XNamespace ns = new XNamespace ( "my namespace" )
使用隐式/显式转换而不是构造函数背后的想法是什么?方便?
有这方面的指导方针吗?
方便?
或多或少,是的。考虑当您有一个类似数字的对象(例如 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);
}
}
当然,这种微优化是否有效是另一个问题。
我相信,对 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 对象具有完全相同的命名空间和完全相同的本地名称,它们将共享同一个实例。为此,还明确提供了相等和比较运算符。
除其他好处外,此功能允许更快地执行查询。在过滤元素或属性的名称时,谓词中表示的比较使用身份比较,而不是值比较。确定两个引用实际上指向同一个对象比比较两个字符串要快得多。
您不能在构造函数中提供原子化,但定义转换允许您从池中选择相应的对象并将其返回,就好像它是一个新实例一样。
使用隐式/显式转换是方便的问题,许多编程指南建议您避免使用显式ConvertToXXX
方法。
问题之一是隐式/显式转换的使用进一步重载了强制转换运算符的函数。它赋予了它双重目的
不幸的是,C# 已经在其他领域做了后者(使用原语和装箱)。
如果两个类应该可以相互转换,但它们不共享自动允许这种行为的基类的接口,则可以使用转换。隐式转换永远不应该有数据丢失的可能性;它们通常被认为是“扩大”转换。例如,将 a 转换int
为 along
是一种扩展转换,并且隐式转换没有固有的问题。显式转换可能涉及数据丢失的可能性;along
可能会或可能不会转换为 a int
,具体取决于其值。
我在隐式转换中使用的一个技巧是,当我没有其他合理的选择时,将不同命名空间中的类相互转换。例如,一个 WCF 服务返回一个 AuthenticationToken 对象,我需要将该对象传递给不同命名空间中的 WCF 服务。两者都有这个 AuthenticationToken 对象,并且不断的转换会很痛苦。我的解决方案涉及public static implicit operator
在部分类中使用以添加以每种方式进行转换的功能。
就个人而言,当我知道 rhs 可以转换为类的静态成员时(比如说color = "red"
to imply color = Colors.Red
) ,我会使用转换
当我打算实际创建一个新实例时,我使用 new 运算符。