CultureInfo & NumberFormatInfo
От: 3332560  
Дата: 13.07.16 10:28
Оценка:
Добрый день.

Имеется приложение, которое хостит ряд однотипных плагинов (MEF), каждый плагин работает с одной или двумя сетевыми службами у которых различаются числовые форматы и форматы времени. В дополнение к этому приложение пишет лог файлы, в которых выводит полученные от служб данные и в этих логах хочется получить единообразное отображение данных, при этом избавившись от необходимости указания правил форматирования при каждом вызове метода ToString().

Собственно проблем с этим нет, я реализовал для каждой службы свой экземпляр NumberFormatInfo и еще один дополнительный для отображения данных в логах. Но, возник вопрос, как правильнее всего перегружать стандартные значения ОС? Те я могу в контексте каждого плагина поменять значение у текущего потока следующим образом:

Thread.CurrentThread.CurrentCulture.NumberFormat = service1nfi;


Но мне это кажется не правильным способом. Впрочем описывать дополнительные культуры для каждой службы тоже не хочется.
Re: CultureInfo & NumberFormatInfo
От: Sinix  
Дата: 13.07.16 11:39
Оценка:
Здравствуйте, 3332560, Вы писали:

3>Собственно проблем с этим нет, я реализовал для каждой службы свой экземпляр NumberFormatInfo и еще один дополнительный для отображения данных в логах. Но, возник вопрос, как правильнее всего перегружать стандартные значения ОС?


Самый правильный способ — передавать культуру явно, тем более что MEF.

Если лень — обновиться на 4.6 и изменять CultureInfo.CurrentCulture. См секцию How a Thread's Culture Is Determined и пример в этой секции.

Для предыдущих версий фреймворка можно попытать счастья с вот этой магией.
Re[2]: CultureInfo & NumberFormatInfo
От: 3332560  
Дата: 13.07.16 11:58
Оценка:
Здравствуйте, Sinix, Вы писали:

S>Здравствуйте, 3332560, Вы писали:


S>Самый правильный способ — передавать культуру явно, тем более что MEF.


S>Если лень — обновиться на 4.6 и изменять CultureInfo.CurrentCulture. См секцию How a Thread's Culture Is Determined и пример в этой секции.


Я на 4.6
Но, проблема в том, что, мне не надо менять именно саму культуру... Наверное, я плохо описал свою ситуацию.

Плагин1 работает со службой1 и со службой2 (службы, это полностью не подвластные мне сторонние приложения). Работа происходит по средствам обращения к API службы. Для примера пуст обе службы отдают данные в формате англо язычной культуры, но у службы1 разделителем у дробных числе является точка, а у второй запятая (да это полностью не корректно, но вот у меня акая ситуация). И мне приходится по всему коду плагина управлять правилами форматирования строк и правилами преобразования чисел, что очень не удобно. Хочется получить простой способ контроля над этим делом, собственно для этого я создаю инстансы NumberFormatInfo персонально для каждой службы, вопрос, как правильнее ими воспользоваться для переопределения параметров языковой культуры. И стоит ли в таком случае создавать новые культуры для службы ?
Re[3]: CultureInfo & NumberFormatInfo
От: Sinix  
Дата: 13.07.16 12:19
Оценка:
Здравствуйте, 3332560, Вы писали:


3>Плагин1 работает со службой1 и со службой2 (службы, это полностью не подвластные мне сторонние приложения). Работа происходит по средствам обращения к API службы. Для примера пуст обе службы отдают данные в формате англо язычной культуры, но у службы1 разделителем у дробных числе является точка, а у второй запятая (да это полностью не корректно, но вот у меня акая ситуация).


ну как всегда, смотрим на корень проблемы:
        // double.cs
        public override String ToString() {
            Contract.Ensures(Contract.Result<String>() != null);
            return Number.FormatDouble(m_value, null, NumberFormatInfo.CurrentInfo);
        }
и
        // numberformatinfo.cs
        public static NumberFormatInfo CurrentInfo {
            get {
                System.Globalization.CultureInfo culture = System.Threading.Thread.CurrentThread.CurrentCulture;
                if (!culture.m_isInherited) {
                    NumberFormatInfo info = culture.numInfo;
                    if (info != null) {
                        return info;
                    }
                }
                return ((NumberFormatInfo)culture.GetFormat(typeof(NumberFormatInfo)));
            }
        }


Соответственно варианта два: или вы подменяете CurrentThread.CurrentCulture на время работы с каждой службой, или передаёте NumberFormatInfo явно для каждой форматируемой/разбираемой строки. После того как сделаете выбор, можно будет обсуждать конкретные варианты.

P.S. Передавать только NumberFormatInfo — путь к _очень_ интересным граблям. Подменяйте всю культуру целиком, так меньше шансов ошибиться.
Re[4]: CultureInfo & NumberFormatInfo
От: 3332560  
Дата: 14.07.16 14:38
Оценка:
Здравствуйте, Sinix, Вы писали:

S>ну как всегда, смотрим на корень проблемы:

S>
S>        // double.cs
S>        public override String ToString() {
S>            Contract.Ensures(Contract.Result<String>() != null);
S>            return Number.FormatDouble(m_value, null, NumberFormatInfo.CurrentInfo);
S>        }
S>
и

S>
S>        // numberformatinfo.cs
S>        public static NumberFormatInfo CurrentInfo {
S>            get {
S>                System.Globalization.CultureInfo culture = System.Threading.Thread.CurrentThread.CurrentCulture;
S>                if (!culture.m_isInherited) {
S>                    NumberFormatInfo info = culture.numInfo;
S>                    if (info != null) {
S>                        return info;
S>                    }
S>                }
S>                return ((NumberFormatInfo)culture.GetFormat(typeof(NumberFormatInfo)));
S>            }
S>        }
S>


Я просмотрел приведенные вами участки кода до дыр, но я не вижу (не понимаю) "корня" проблемы. Вы хотите отметить плохой дизайн данных методов?

S>Соответственно варианта два: или вы подменяете CurrentThread.CurrentCulture на время работы с каждой службой, или передаёте NumberFormatInfo явно для каждой форматируемой/разбираемой строки. После того как сделаете выбор, можно будет обсуждать конкретные варианты.


S>P.S. Передавать только NumberFormatInfo — путь к _очень_ интересным граблям. Подменяйте всю культуру целиком, так меньше шансов ошибиться.


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

Я так же несколько раз перечитал данную статью с MSDN NumberFormatInfo, но по прежнему нахожусь в глубоком замешательстве как именно в моем случае стоит поступить наиболее правильно. Пока имеются лишь следующие идеи:

1. произвести наследование от "правильной" языковой культуры, для выше озвученного примера от en-US
2. в наследнике подменить значения NumberFormatInfo собственным экземпляром созданным через конструктор
3. аналогично поступить для DateTimeFormatInfo
4. подменить значение CurrentThread.CurrentCulture на культуру службы перед началом работы с ней

Но меня терзают куча сомнений. Хочется раз и навсегда разобраться для себя в данном вопросе и перестать избегать его. Спасибо.
Re[5]: CultureInfo & NumberFormatInfo
От: Sinix  
Дата: 14.07.16 18:03
Оценка:
Здравствуйте, 3332560, Вы писали:

3>Я просмотрел приведенные вами участки кода до дыр, но я не вижу (не понимаю) "корня" проблемы. Вы хотите отметить плохой дизайн данных методов?

Нет, при чём здесь дизайн? Намёк был про невозможность передать NumberInfo кроме как двумя перечисленными выше способами.

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


Как всегда для таких вещей: подменяем что-то глобальное — пишем тест на работоспособность вместе с тасками, await и тыды и тыпы. Вроде бы понятное правило, но тем не менее, на эти грабли наступают все по одному разу как минимум

Я это дело освежил буквально сегодня, успешнейше положив тесты на билдсервере

3>Я так же несколько раз перечитал данную статью с MSDN NumberFormatInfo, но по прежнему нахожусь в глубоком замешательстве как именно в моем случае стоит поступить наиболее правильно. Пока имеются лишь следующие идеи:


Ну да, именно так. См CultureAndRegionInfoBuilder
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.