stringvb.netdoubletostring

Why does calling ToString give different results with a Double returned by CDbl and a Double returned by Double.Parse?


Demo code:

        System.Console.WriteLine($"CDbl:         {(CDbl("234.56"))} {(CDbl("234.56")).GetType} {(CDbl("234.56")).ToString("0.0")}")
        System.Console.WriteLine($"Double.Parse: {(Double.Parse("234.56", usCulture))} {(Double.Parse("234.56", usCulture)).GetType} {(Double.Parse("234.56", usCulture)).ToString("0.0")}")

Output:

CDbl:         234.56 System.Double 234.6
Double.Parse: 234.56 System.Double 2

The second line is printing the most significant digit of the number (if it's 345.67, it prints 3).

In Visual Studio, mousing over the ToString calls seems to show that the first line is using Double.ToString while the second is using Object.ToString. Is this related? If so, why does this happen?

different versions of ToString


Solution

  • Based on the information that Intellisense is providing, I have to assume your VB.NET Project is setup like this:

    Option Explicit set to On
    Option Strict set to Off
    Option Infer set to Off

    Also, as confirmed in the comments, you have declared the CultureInfo variable without specifying the Type explicitly:

    Dim usCulture = CultureInfo.InvariantCulture
    

    If you inspect the variable Type, you should verify that it's actually declared as Object, since its Type is not specified and the compiler's options are setup as described.

    CDbl uses Microsoft.VisualBasic.CompilerServices.Conversions.ToDouble() conversion service. It's compiled inline. In this case, the underlying conversion method is boxing a double. The following ToString() call already knows what it deals with.

    Double.Parse() ends up working differently in this context.
    Your CultureInfo variable is declared as Object. Probably everything not declared explicitly is treated as an Object Type. So is the result of the method call. The compiler is going to crete a Late Binding call (Microsoft.VisualBasic.CompilerServices.NewLateBinding.LateGet()) that returns an Object Type.
    Then you get Object.ToString()

    Declaring explicitly the CultureInfo variable:

    Dim usCulture As CultureInfo = CultureInfo.InvariantCulture
    

    Then the Double.Parse() call does not require Late Binding and you get Double.ToString() (which is still a call to String.Format(), BTW)


    I suggest setting all the aforementioned Options to On.
    Possibly, in the Visual Studio's Tools -> Options -> Projects and Solutions -> VB Defaults section, so this setup is predefined for all new Projects.