Как исправить приложение, которое имеет проблему с десятичным разделителем - PullRequest
8 голосов
/ 21 июня 2011

Этот пост о C # и .Net, но некоторая информация полезна для других технологий.

Насколько я помню, у меня были проблемы с приложениями или играми, которые вылетали из-за другого стиля анализа десятичных чисел. Это происходит очень часто, от приложений САПР, библиотек до веб-страниц. Я не уверен, что это невежество или отсутствие знаний, но это действительно раздражает.

В чем проблема? Здесь - это статья в вики, но короткая:

Вот карта, которая показывает, какой тип десятичного разделителя (десятичной метки) используется во всем мире. map of diffrent decimal separator

Десятичные знаки:

  • Период - синий
  • Запятая - Зеленый
  • незападно-арабские цифры - красный
  • Неизвестно - серый

Большинство стран Европы, Южной Америки пишут 1 000 000,00 или 1000000,00, иногда 1.000.000,00, в противоположность «имперскому» (отмечен синим), пишут 1 000 000,00

Позвольте мне дать вам несколько из всех проблем, которые я решал в прошлом месяце.

  1. Номер на веб-страницах, трудно читаемых: Возьмем одно из самых просмотренных видео YT . Это показывает мне 390159851. Числа свыше миллиона очень трудно читать, каков порядок? Это 39 млн или 390?
  2. Mirosoft Пример XNA для Windows Phone 7 : Существует очень удобный класс, который анализирует XML-файл для создания анимации XNA

    /// <summary>
    /// Loads animation setting from xml file.
    /// </summary>
    private void LoadAnimiationFromXML()
    {
        XDocument doc = 
                  XDocument.Load("Content/Textures/AnimationsDefinition.xml");
        XName name = XName.Get("Definition");
        var definitions = doc.Document.Descendants(name);
    
    
            if (animationDefinition.Attribute("Speed") != null)
            {
                animation.SetFrameInvterval(TimeSpan.FromMilliseconds(
                    double.Parse(animationDefinition.Attribute("Speed").Value)));
            }
    

    double.Parse выдает исключение, одной простой подсказкой является использование XmlConvert.ToDouble(); или разбор с InvariantCulture.

  3. .Net приложение, которое использует CSV-файлы для хранения входного вектора как CSV - также выдает.

  4. Еще одно приложение .Net, в котором есть разбор внутри класса - throws.

Так как мы можем это исправить?

  • Исправить ошибку в коде - возможно только с доступным исходным кодом и утомительно.
  • Изменение данных (CVS, XML и т. Д.) - даже с возможными, не очень довольными изменением данных.
  • Измените десятичный разделитель по умолчанию для ОС - этого не произойдет.

Есть ли другой способ решить эту проблему? Можно ли сделать приложение инвариантным? Как запуск приложения в другой среде.

PS. Я хотел бы запустить приложение, но у меня нет кода.

Ответы [ 5 ]

6 голосов
/ 21 июня 2011

Правильно установите Thread.CurrentThread.CurrentCulture, и у вас не будет таких проблем. Читайте здесь как писать код, независимый от культуры.

EDIT: Если у вас нет доступа к коду, вы можете запустить приложение под учетной записью пользователя, для которой установлен ожидаемый уровень культуры. Для быстрого доступа вы можете создать английского пользователя, немецкого пользователя, французского пользователя ..

1 голос
/ 21 июня 2011

Нет другого способа решить эту проблему, просто исправьте это в коде.
Если вы захотите запустить FxCop , вы скоро научитесь всегда передавать действительный CultureInfo каждому возможному ToString() или Parse() метод.Честно говоря, так и должно быть, даже если вы знаете, что CultureInfo.CurrentCulture используется по умолчанию.
Всегда передавая IFormatProvider, вы говорите другим разработчикам:

  1. ToString(CultureInfo.CurrentCulture)или Parse(whatever, CultureInfo.CurrentCulture) - это то, что конечный пользователь увидит или сможет ввести, поэтому нам нужно позаботиться о его / ее культурном происхождении.
  2. ToString(CultureInfo.InvariantCulture) или Parse(whatever, CultureInfo.InvariantCulture) - это то, что мы используем внутренне и это не предназначено для показа пользователю.

Теперь я знаю, что это звучит как большая работа, но это просто то, чтодолжно быть сделано.Возможно, вы просто хотели бы поблагодарить какую-то бедную душу в Microsoft, которая своим добрым намерением решила, что CurrentCulture для конечного пользователя является лучшим значением по умолчанию для провайдеров форматирования ... Очевидно, что другие разработчики фреймворков, которые делали это в прошлом, были неправы и люди изМС правы, ха?Большая часть денег испарилась из-за этой глупой, неустранимой ошибки.

1 голос
/ 21 июня 2011

Здесь нет серебряной пули.

Некоторые предложения:

Инвариантная культура может использоваться при работе с внутренними данными, которые хранятся в файле конфигурации. Таким образом, независимо от культуры, вы можете последовательно считывать и записывать свои собственные внутренние данные.

Смотрите здесь:

http://msdn.microsoft.com/en-us/library/4c5zdc6a.aspx

Другие проблемы связаны с чем-то простым, например string.ToLower ().

Кажется достаточно невинным, пока вы не попробуете строчные буквы английского алфавита, чем в современной культуре. (Например, турецкий)

В этих случаях вызов string.ToLower () должен быть заменен перегрузкой культуры, и текущая культура или инвариантная культура должны быть переданы (в зависимости от вашей ситуации).

Определенно, есть некоторые подводные камни, на которые стоит обратить внимание.

1 голос
/ 21 июня 2011

Я чувствую вашу боль, порт RunKeeper для Windows Phone 7 ошибся и сообщил, что в прошлом месяце я нарушил скорость света в 100 000 раз.

Если вы небрежны, вы столкнетесь с этими проблемами, но по большей части их можно избежать. Строго говоря, вы всегда должны представлять информацию в ее локализованном формате, а затем преобразовывать ее в независимое от культуры или базовое значение при сохранении. Таким образом, вы всегда можете ориентироваться на конкретные культуры.

Проблема, с которой, я полагаю, сталкиваются многие разработчики .NET, заключается в том, что они не понимают, что все стандартные методы синтаксического анализа работают на Thread.CurrentThread.CurrentCulture, и используют определенный формат чисел для этой культуры, и то же самое с датами и часовыми поясами. .

Что-то, что я мог бы рассмотреть, это настроить цепочку ответственности, в которой сначала запрашивались варианты, специфичные для культуры, и запасной вариант, не зависящий от культуры. Я бы никогда не смешивал их, но поддержал бы независимое от культуры значение по умолчанию, которое должно работать, если вы придерживаетесь какого-то типичного соглашения (например, английские числовые форматы). Но каждый раз это может быть неправильным выбором. Обучите пользователя, если он считает, что анализ CSV-файла смешанного числового формата - это правильное решение.

1 голос
/ 21 июня 2011

На мой взгляд, подход должен быть следующим:

  1. во внутреннем хранилище, цифры просто цифры.так что никаких проблем не возникает.
  2. при разборе исходных текстовых источников вы должны анализировать их в соответствии с локалью, в которой создан источник - наиболее вероятно, инвариантная культура
  3. при выводе значений пользователю, отформатируйте их в соответствии с предпочтительным языком пользователя.в C # это означает сохранение CurrentCulture (не CurrentUICulture, см. здесь почему).

Это должно быть относительно просто и охватывать все случаи.

Это все относится к случаю, когда вы являетесь автором приложения.Для других приложений соответствующие разработчики должны сами исправить свои ошибки.

...