FreeDev
FreeDev

Reputation: 141

Convert string to double do not respect current number decimal separator

I'm trying to convert a string representing a double from invariant culture to a double in current culture representation, I'm concerned with how to get the new double representation to use the current number decimal separator of Current Culture.

I used the code below for the conversion :

public static double ConvertToDouble(this object inputVal, bool useCurrentCulture = false)
{
    string currentSep = CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator;
    string invariantSep = CultureInfo.InvariantCulture.NumberFormat.NumberDecimalSeparator;
    if (inputVal.GetType() == typeof(string))
    {
        if (!currentSep.Equals(invariantSep))
        {
            inputVal = (inputVal as string).Replace(invariantSep, currentSep);
        }
    }
    if (useCurrentCulture)
        return Convert.ToDouble(inputVal, CultureInfo.CurrentCulture);
    else
        return Convert.ToDouble(inputVal);
}

But the above code always gives me a double with ".", although I use the CurrentCulture for example French supposed to give me a double with comma (",").

Many thanks in advance for any hint.

FreeDev

Upvotes: 0

Views: 1061

Answers (2)

Tim Schmelter
Tim Schmelter

Reputation: 460350

From the comments and your question i guess that you actually want to convert a string to a double with either InvariantCulture or current-culture. This double should then be converted to a string which is formatted by the current-culture datetime-format informations(like NumberDecimalSeparator).

So this method should do two things:

  1. parse string to double
  2. convert double to string

public static string ConvertToFormattedDouble(this string inputVal, IFormatProvider sourceFormatProvider = null, IFormatProvider targetFormatProvider = null)
{
    if (sourceFormatProvider == null) sourceFormatProvider = NumberFormatInfo.InvariantInfo;
    if (targetFormatProvider == null) targetFormatProvider = NumberFormatInfo.CurrentInfo;
    if (sourceFormatProvider == targetFormatProvider)
        return inputVal; // or exception?

    double d;
    bool isConvertable = double.TryParse(inputVal, NumberStyles.Any, sourceFormatProvider, out d);
    if (isConvertable)
        return d.ToString(targetFormatProvider);
    else
        return null; // or whatever
}

You can use it in this way:

string input = "1234.567";
string output = input.ConvertToFormattedDouble();  // "1234,567"

Note that i've extended string instead of object. Extensions for object are a bad idea in my opinion. You pollute intellisense with a method that you 'll almost never use (although it applies also to string).


Update:

If you really want to go down this road and use an extension for object that supports any kind of numbers as (boxed) objects or strings you could try this extension:

public static string ConvertToFormattedDouble(this object inputVal, IFormatProvider sourceFormatProvider = null, IFormatProvider targetFormatProvider = null)
{
    if (sourceFormatProvider == null) sourceFormatProvider = NumberFormatInfo.InvariantInfo;
    if (targetFormatProvider == null) targetFormatProvider = NumberFormatInfo.CurrentInfo;

    if (inputVal is string)
    {
        double d;
        bool isConvertable = double.TryParse((string)inputVal, NumberStyles.Any, sourceFormatProvider, out d);
        if (isConvertable)
            return d.ToString(targetFormatProvider);
        else
            return null;
    }
    else if (IsNumber(inputVal))
    {
        decimal d = Convert.ToDecimal(inputVal, sourceFormatProvider);
        return Decimal.ToDouble(d).ToString(targetFormatProvider);
    }
    else
        return null;
}

public static bool IsNumber(this object value)
{
    return value is sbyte
            || value is byte
            || value is short
            || value is ushort
            || value is int
            || value is uint
            || value is long
            || value is ulong
            || value is float
            || value is double
            || value is decimal;
}

Usage:

object input = 1234.56745765677656578d;
string output = input.ConvertToFormattedDouble();  // "1234,56745765678"

Upvotes: 0

Jon Skeet
Jon Skeet

Reputation: 1503954

But the above code always gives me a double with "." as the NumberDecimalSeparator

No, it returns a double. A double is just a number. It doesn't have a NumberDecimalSeparator... only a culture does, and that's only applied when converting to or from strings. Talking about the separator for a double is like talking about whether an int is in decimal or hex - there's no such concept. 0x10 and 16 are the same value, represented by the same bits.

It's not really clear what you're trying to do, but it's crucial to understand the difference between what's present in a textual representation, and what's inherent to the data value itself. You should care about the separator when parsing or formatting - but after you've parsed to a double, that information is gone.

Upvotes: 2

Related Questions