为什么存在Convert.ToInt32(Int32)?

25

有一种Convert.ToInt32的过载函数,它接受Int32作为参数。但即使文档中基本上什么也没有说,该方法返回其输入。

问题是,为什么我们有这样的过载函数? 它有任何目的吗? 有人可以给我使用此方法的示例吗?

我的想法: 我认为我们可能会拥有这个函数重载是因为有一个函数可以接受对象(Object)作为参数,因此我们想要消除装箱等操作。 但我不确定。


7
我们也有string.ToString()方法。我确信这里可能有重复的问题,但像往常一样我找不到它。 - Soner Gönül
2
它与许多Convert方法保持一致(例如ToBoolean(Boolean))。值得记住的是,Convert类早于泛型,并不一定是构建API的最佳方式。 - Damien_The_Unbeliever
3
也许可以用于反思? - Fredou
4
不,String.ToString非常不同,因为它是重写的虚拟方法。它仅仅是运行时所需。 - Georg
还有其他的Convert.To...方法,这些方法没有任何意义。例如Convert.ToBoolean(DateTime) - 它总是会抛出一个InvalidCastException异常。https://msdn.microsoft.com/en-us/library/efbxsx53.aspx 因此,我认为对于这个问题不存在有用的答案。 - Koopakiller
显示剩余8条评论
5个回答

18

我的想法:

  • 用于代码生成:特别是在 .NET 2.0 中,许多代码(例如类型化数据集)都是生成的。像 Convert.ToInt32(Int32) 这样的过载简化了代码生成器,但不会影响运行时性能,因为调用可能立即被 JIT 转换掉。
  • 用于一致性:自 .NET 2.0 或甚至自 1.0 以来,就有一个名为 IConvertible 的接口,它由 Convert 类使用。此接口要求方法如 ToInt32 等。

代码生成(更多细节): 在 .NET 2.0 时代,生成代码的常规方法是使用 System.CodeDOM,因为它提供了重用同一代码生成器的手段,最著名的是 VB.NET 和 C#。在 CodeDOM 中,你不需要知道给定表达式的类型即可调用方法,只需在目标对象表达式和方法名称上创建 CodeMethodCallExpression 即可。另一方面,CodeDOM 不支持许多强制转换操作符,例如 C# 的 as 操作符。

因此,在 CodeDOM 中,通常很难知道给定代码表达式的类型。这完全有意义,因为表达式可能涉及的许多方法也是生成代码的一部分,因此在生成时未知。然而,在某些情况下,您需要将特定表达式转换为给定类型,例如 System.Int32。我可以想象这实际上发生在类型化数据集中,尽管我不确定百分之百。由于存在 Convert.ToInt32,生成器不需要知道给定表达式是否为 System.Int32 类型。当编译器编译生成的代码时,所有方法签名都可用,编译器可以确定表达式的类型为 System.Int32 并调用适当的重载。

在另一方面,JIT编译器将检测到方法Convert.ToInt32只会返回其参数。但是由于该方法不是虚拟的,所以可以将方法体插入调用者的代码中,而不是调用Convert.ToInt32,因为调用该方法的开销比方法本身要高得多。


接口不适用于静态成员。 - Theodoros Chatzigiannakis
@TheodorosChatzigiannakis 是的,我知道,但基本上 Convert 类反映了 Convert 类的签名。 - Georg
1
我认为代码生成是非常准确的。在 C# 的早期版本中,特别是在泛型和表达式树出现之前,有很多代码生成。这也解释了为什么你会看到使用 Convert.ToInt32 而不是更具体的东西,比如 int.Parse(int)value 等等。 - Luaan

5

只有API设计者知道。

如果非要猜测的话,我会猜测这是为了保持一致性——例如,当您使用反射动态创建调用时,如果您可以假设每个Convert.ToX(Y)组合都存在于任何基本类型XY中,那么就更容易了。


1
我们可以从框架类中ToInt32(Int32)的用法中得出一个可能的答案。
例如: System.Activities.DurableInstancing.SerializationUtilities
public static byte[] CreateKeyBinaryBlob(List<CorrelationKey>correlationKeys)
{
     [...]
     Convert.ToInt32(correlationKey.BinaryData.Count)

and System.ComponentModel.Design.CollectionEditor

private void PaintArrow(Graphics g, Rectangle dropDownRect)
{
    Point point = new Point(Convert.ToInt32(dropDownRect.Left + dropDownRect.Width / 2), Convert.ToInt32(dropDownRect.Top + dropDownRect.Height / 2));

在这两种情况下,我们可以看到属性或表达式的类型目前为Int32,但有合理的预期,即在不同平台、CPU架构、框架未来版本等情况下,该类型可能会有所不同。
因此,我的建议是将其作为源代码的一种未来证明方式存在,即使某些关键“实体”(如窗口X和Y坐标)更改类型,也可以编译而无需修改。

如果说使用双精度的RectanglePaintArrow方法中是为了未来的兼容性,那么你会期望使用支持双精度的Point对象。程序员可能认为即使使用支持更大类型的Rectangle对象实例化时,也要强制使用Int32 Point对象。这样做的好处是,当使用更准确的类型时,就不会出现错误/误解,因此它与图形(或blob大小)无关。 - Jeremy Thompson

0

这是方法的描述:

    //
    // Summary:
    //     Returns the specified 32-bit signed integer; no actual conversion is performed.
    //
    // Parameters:
    //   value:
    //     The 32-bit signed integer to return.
    //
    // Returns:
    //     value is returned unchanged.

我能想到的唯一可能是,如果输入已经是一个int,那么它就是一个快捷方式/直通车。这比将int传递给Convert.ToInt32(object)要高效得多。


0

公共语言运行时在内部使用IConvertible接口。由于CLR基本类型是Boolean、SByte、Byte、Int16、UInt16、Int32、UInt32、Int64、UInt64、Single、Double、Decimal、DateTime、Char和String,因此在Convert类中为每个类型都提供了实现。

但是,例如,Convert.toBoolean(DateTime)总是按设计返回异常。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接