Как работать с числами с плавающей запятой в С#?

206
29 марта 2018, 06:03

Есть вот такой код простого конвертера валют. (SOM - это валюта Кыргызстана)

using System;
namespace modConvertUSDRU
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Hello\n");
            Console.WriteLine("Введите 1 если USD/SOM или 2 если SOM/USD");
            double ENTER = Convert.ToDouble(Console.ReadLine());
            switch (ENTER)
            {
                case 1:
                    ConvrtRUUSD();
                break;
                case 2:
                    ConverUSDRU();
                break;
            }
        }
        static void ConverUSDRU()
        {
            double convertUSRU;
            Console.WriteLine("Введите сумму в сомах: ");
            double RU = Convert.ToDouble(Console.ReadLine());
            Console.WriteLine("Введите курс USD: ");
            double USD = Convert.ToDouble(Console.ReadLine());
            convertUSRU = RU / USD;
            Console.WriteLine("Сумма равна {0} $.", convertUSRU);
        }
        static void ConvrtRUUSD()
        {
            double convertUSRU;
            Console.WriteLine("Введите сумму в USD: ");
            double USDSUM = Convert.ToDouble(Console.ReadLine());
            Console.WriteLine("Введите курс USD: ");
            double USDK = Convert.ToDouble(Console.ReadLine());
            convertUSRU = USDSUM * USDK;
            Console.WriteLine("Сумма равна {0} сом.", convertUSRU);
        }
    }
}

на красоту не смотрим это просто пример!

вопрос в следующим: Почему при вводе к примеру (16000) все работает при вводе (16,000) тоже, а вот при вводе (16.000) выдаёт вот такую ошибку

Unhandled Exception: System.FormatException: Input string was not in a correct format.
at System.Number.ParseDouble(String value, NumberStyles options, NumberFormatInfo numfmt)
at modConvertUSDRU.Program.ConverUSDRU() in D:\MailCloud\C#\CS2017WORK\modConvertUSDRU\Program.cs:line 32
at modConvertUSDRU.Program.Main(String[] args) in D:\MailCloud\C#\CS2017WORK\modConvertUSDRU\Program.cs:line 20*

Я понимаю что конфликт может быть в каком-то исключении или дело в конфликте (string/double) предположения есть, но где ошибка понять не могу!

Answer 1

Ваша проблема заключается в том, что определенные страны имеют свои стандарты. К примеру Америка, у них футы, мили и прочие для нас неведомые показатели. У нас принято все считать в метрах, километрах и других стандартных для нас величин.

Как не странно, но и принятые стандарты в написание чисел тоже у многих стран разные. Где то принято разделять число запятой (123,456), а где то для этого используется точка (123.456). Язык C# в этом плане тоже еще тот любитель все сверять с культурой и в связи с этим, он не даст вам перевести значение с точкой к примеру с ES культурой (ну или с EN культурой не удастся перевести значение с запятой.).

Пару примеров:

Thread.CurrentThread.CurrentCulture = new CultureInfo("en");
Console.WriteLine(double.Parse("123.456"));
Console.WriteLine(double.Parse("123,456"));

Значение с точкой отобразилось правильно, а вот значение с запятой саму , попросту откинул и выдал 123456.

Thread.CurrentThread.CurrentCulture = new CultureInfo("es");
Console.WriteLine(double.Parse("123.456"));
Console.WriteLine(double.Parse("123,456"));

Тут у нас значение с точкой - саму точку теряет (123456), а значение с запятой отображается как надо.

Thread.CurrentThread.CurrentCulture = new CultureInfo("ru");
Console.WriteLine(double.Parse("123.456"));
Console.WriteLine(double.Parse("123,456")); 

А в этом варианте мы получим ошибку System.FormatException: "Входная строка имела неверный формат." (на строке с точкой), ибо русская культура не воспринимает точку.

Так как быть в таком случае, если надо и то и то значение вытащить?

  1. Можем указать культуру явно:

    CultureInfo culture = new CultureInfo("en");
    Console.WriteLine(double.Parse("123.456", culture));
  2. Можно попробовать предварительно указать культуру и у нашего string значения заменять один знак на другой:

    Thread.CurrentThread.CurrentCulture = new CultureInfo("ru");
    Console.WriteLine(double.Parse("123.456".Replace(".", ",")));
    Console.WriteLine(double.Parse("123,456"));
  3. Можно попробовать воспользоваться таким велосипедом (вызов будет GetDouble("123,456", 0), 0 - значение, если нечего не вышло перевести)):

    public static double GetDouble(string value, double defaultValue)
    {
        //Пробуем получить значение в текущей культуре
        if (!double.TryParse(value, NumberStyles.Any, CultureInfo.CurrentCulture, out var result) &&
            //Пробуем получить в en культуре
            !double.TryParse(value, NumberStyles.Any, CultureInfo.GetCultureInfo("en-US"), out result) &&
            //Пробуем получить в нейтральной культуре
            !double.TryParse(value, NumberStyles.Any, CultureInfo.InvariantCulture, out result))
        {
            result = defaultValue; //Значение, если нечего не вышло
        }
        return result;
    }
  4. Еще как вариант, это задавать значение NumberDecimalSeparator, которое собственно и отвечает за то, какой символ используется в культуре:

    var clone = (CultureInfo)CultureInfo.InvariantCulture.Clone();
    clone.NumberFormat.NumberDecimalSeparator = ".";
    Console.WriteLine(double.Parse("123.456", clone));
    Console.WriteLine(double.Parse("123,456"));
    //Или
    NumberFormatInfo format = new NumberFormatInfo {NumberDecimalSeparator = "."};
    Console.WriteLine(double.Parse("123.456", format));
    Console.WriteLine(double.Parse("123,456"));

В общем, пробуйте. Удачи!

READ ALSO
c# WebBrowser Как при открытии сайтов игнорировать x-frame-options:?

c# WebBrowser Как при открытии сайтов игнорировать x-frame-options:?

При открытии сайтов должны игнорироваться x-frame-options (запрет на открытие некоторых страниц в iframe, в браузерах решается установкой мини-плагина)

206
Проект крашится после установки

Проект крашится после установки

Проблема следующая: создан проект wpf (с использованием фреймов и страниц)В отладке все стабильно работает, но после установки запускается...

205
Проблема с FileStream [требует правки]

Проблема с FileStream [требует правки]

Добрый день, пытаюсь произвести сериализацию объекта на C# через FileStream, но почему то конструктор FileStream "ругается" на запись пути к файлуКод:

211
CefSharp Использование proxy с логином и паролем

CefSharp Использование proxy с логином и паролем

Такая реализация не работает, вместо браузера просто белый экран

223