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

发布于 2024-09-25 18:05:32 字数 216 浏览 3 评论 0原文

一个例子是:

XNamespace ns = "my namespace"

为什么不?:

XNamespace ns = new XNamespace ( "my namespace" )

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

有这方面的指南吗?

An example would be:

XNamespace ns = "my namespace"

Why not?:

XNamespace ns = new XNamespace ( "my namespace" )

What's the idea behind using implicit/explicit convertions instead of constructors? Convenience?

Is there a guideline for this?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

氛圍 2024-10-02 18:05:33

方便吗?

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

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

是非常烦人且难以阅读的。隐式转换在这里很有帮助(在本例中,另一种选择是运算符重载,但这会导致许多类似的重载)。

有这方面的指南吗?

提供尽可能少的隐式转换,因为它们可能隐藏问题。隐式转换在增加简洁性的同时,也降低了明确性。有时这很好,但有时则不然。

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

在 VB 中,隐式转换称为“加宽”(与缩小相反,后者是显式),这很好地描述了它:无信息在转换过程中丢失。

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

考虑我的复杂示例。我们可能想要缓存常用的复数的值:

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);
    }
}

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

Convenience?

More or less, yes. Consider the case for when you’ve got a number-like object (say, a Complex) on which you do calculations. Clearly, writing code such as:

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

is very annoying and hard to read. Implicit conversions help here (an alternative would be operator overloads in this example, but that would lead to lots of similar overloads).

Is there a guideline for this?

Provide as few implicit conversions as possible, since they may hide problems. Implicit conversion reduce explicitness by the same amount by which they increase terseness. Sometimes this is good, but sometimes not.

I find it best to restrict implicit conversions to very similar types, such as the number-like objects in my example above: an int essentially is-a Complex (from a mathematical standpoint; even if it’s not modelled via inheritance), hence an implicit conversion makes sense.

In VB, an implicit conversion is called “Widening” (as opposed to Narrowing, which is explicit) and this describes it well: no information is lost in the course of the conversion.

Furthermore, an operator is essentially a builder function, and has (some of) the usual advantages of a builder function over a constructor: namely, it can re-use cached values instead of always creating new instances.

Consider my Complex example. We may want to cache values for often-used Complex numbers:

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);
    }
}

Of course, whether this micro-optimization is effective is another question.

娇纵 2024-10-02 18:05:33

我认为,使用 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 对象具有完全相同的命名空间和完全相同的本地名称,它们将共享同一个实例。为此还明确提供了相等和比较运算符。

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

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

One of the reasons behind using implicit conversion with such simple types as XName is, I believe, convenience in calling methods.

For example, you can write

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

Simplicity at extracting data is what LINQ is all about, and if we had to write

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

even for simplest queries, would LINQ be totally worth it for complex ones?

Another important issue here is that XNames are atomized.
See MSDN:

XName objects are guaranteed to be atomized; that is, if two XName objects have exactly the same namespace and exactly the same local name, they will share the same instance. The equality and comparison operators are also provided explicitly for this purpose.

Among other benefits, this feature allows for faster execution of queries. When filtering on the name of elements or attributes, the comparisons expressed in predicates use identity comparison, not value comparison. It is much faster to determine that two references actually refer to the same object than to compare two strings.

You can't provide atomization in constructor, but defining a conversion allows you to pick corresponding object from the pool and return it as if it were a new instance.

寂寞陪衬 2024-10-02 18:05:33

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

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

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

不幸的是,C# 已经在其他领域(使用基元和装箱)实现了后者。

The use of implicit / explicit conversions is issue of convenience and one that many programming guidelines suggest you avoid in favor of explicit ConvertToXXX methods.

One of the problems is tha the use of implicit / explicit conversions further overloads functions of the casting operator. It gives it the dual purpose of

  • Viewing the same object through a different type / interface in the object's hierarchy
  • Coverting the object to a new type altogether

Unfortunately C# already does the latter in other areas (with primitives and boxing).

风月客 2024-10-02 18:05:33

如果两个类应该可以相互转换,但它们不共享自动允许这种行为的基类接口,则您将使用转换。隐式转换永远不应该有数据丢失的可能性;它们通常被认为是“扩大”转换。例如,将 int 转换为 long 是一种加宽转换,并且隐式转换本身不存在问题。显式转换可能会导致数据丢失; long 可能会也可能不会转换为 int,具体取决于它的值。

我在隐式转换中使用的一个技巧是,当我没有其他合理的选择时,将不同名称空间中的类相互转换。例如,一个 WCF 服务返回一个 AuthenticationToken 对象,我需要将其传递给不同命名空间中的 WCF 服务。两者都有这个 AuthenticationToken 对象,不断的转换会很痛苦。我的解决方案涉及在分部类中使用公共静态隐式运算符来添加转换每种方式的功能。

If two classes should be convertible to one another, but they do not share an interface of a base class that allows this behavior automatically, you would use the conversions. Implicit conversions should never have a possibility of data loss; they are often considered "widening" conversions. For example, converting an int to a long is a widening conversion, and there is no problem inherent in the conversion being implicit. Explicit conversions may involve the possibility of data loss; a long may or may not be convertible to an int, depending on its value.

One trick I have used with implicit conversions is to convert classes in different namespaces to each other when I did not have another reasonable option. For example, one WCF service returns an AuthenticationToken object that I need to pass to a WCF service in a different namespace. Both have this AuthenticationToken object, and constant conversion would have been a pain. My solution involved using public static implicit operator in a partial class to add the functionality to convert each way.

-黛色若梦 2024-10-02 18:05:33

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

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

Personally, I use the conversions when I know that the rhs may be converted into a static member of a class (like saying color = "red" to imply color = Colors.Red)

I use the new operator when I intend to actually create a new instance.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文