воскресенье, 7 апреля 2019 г.

Особенности C# для Java-разработчиков


Наверное, все знают, что C# - это мощный язык от великой и могучей компании зла добра Microsoft. Злые языки утверждают, что C# - это просто плохо спроектированная Java, но как же это впечатление обманчиво .
Да, C# был спроектирован под влиянием Java и многие архитектурные решения были взяты оттуда.
Да, код C# выглядит как код Java с нарушением конвенций об именовании.
Тем не менее, если вы Java-разработчик, не впадайте в иллюзию из-за схожести этих двух языков, иначе вас ждут очень странные и неочевидные ошибки, о некоторых из которых я и хочу поговорить.


Сравнение строк

Казалось бы, что может быть проще, чем простое сравнение двух строк на равенство. В Java есть метод Object#equals, который прекрасно решает эту задачу:
    String a = ...;
    String b = ...;

    //как-то так
    boolean eq1 = a.equals(b);
Используя свой опыт разработки, Java-разработчик, программируя на C#, с радостью обнаруживает метод Equals и пишет что-то подобное:
    string a = ...;
    string b = ...;

    //большая ошибка...
    bool eq1 = a.Equals(b);
и может совершить тем самым очень неочевидную ошибку. Если мы воспользуемся в Visual Studio статическим анализатором кода Microsoft FxCop, то он нам любезно выдаст предупреждение:
The behavior of 'string.Equals(string)' could vary based on the current user's locale settings. 
Replace this call in with a call to 'string.Equals(string, System.StringComparison)'.
Анализатор говорит нам, что поведение метода string.Equals(string) может зависеть от настроек пользователя и предлагает воспользоваться методом string.Equals(string, System.StringComparison).
То есть правильный вариант выглядит приблизительно так:
    string a = ...;
    string b = ...;

    bool eq1 = a.Equals(b, StringComparison.Ordinal);
Второй аргумент метода string.Equals(string, System.StringComparison) может принимать следующие значения:

Название константы Назначение
CurrentCulture Сравнивать строки, используя правила сортировки с учетом языка и региональных параметров и текущий язык и региональные параметры.
CurrentCultureIgnoreCase Сравнивать строки, используя правила сортировки с учетом языка и региональных параметров и текущий язык и региональные параметры без учета регистра сравниваемых строк.
InvariantCulture Сравнивать строки, используя правила сортировки с учетом языка и региональных параметров и инвариантный язык и региональные параметры.
InvariantCultureIgnoreCase Сравнивать строки, используя правила сортировки с учетом языка и региональных параметров и инвариантный язык и региональные параметры без учета регистра сравниваемых строк.
Ordinal Сравнивать строки, используя правила обычной (двоичной) сортировки.
OrdinalIgnoreCase Сравнивать строки, используя правила обычной (двоичной) сортировки без учета регистра сравниваемых строк.

Microsoft, видимо, понимает некоторую проблему с пониманием этой таблички, поэтому в помощь к ней предлагает еще такую:

Данные Поведение StringComparison
Внутренние идентификаторы с учетом регистра Нелингвистические идентификаторы с точным соответствием байтов. Ordinal
Идентификаторы с учетом регистра в таких стандартах, как XML и HTTP
Параметры безопасности с учетом регистра
Внутренние идентификаторы без учета регистра Нелингвистические идентификаторы с точным соответствием байтов. OrdinalIgnoreCase
Идентификаторы без учета регистра в таких стандартах, как XML и HTTP
Пути к файлам
Ключи реестра и значения
Переменные среды
Идентификаторы ресурсов (например, имена дескрипторов)
Параметры безопасности без учета регистра
Некоторые сохраненные лингвистически релевантные данные Лингвистически релевантные данные без учета языка и региональных параметров InvariantCulture
InvariantCultureIgnoreCase
Отображение лингвистических данных, требующее фиксированного порядка сортировки
Данные, отображаемые пользователю Пользовательский ввод в большинстве случаев CurrentCulture
CurrentCultureIgnoreCase
Отображение лингвистических данных, требующее фиксированного порядка сортировки

Если суммировать все вышенаписанное, то можно сказать:

Задача На C# На Java
Просто сравнить 2 строки
a.Equals(b, System.StringComparison.Ordinal);
a.equals(b);
Просто сравнить 2 строки без учета регистра
a.Equals(b, System.StringComparison.OrdinalIgnoreCase);
a.equalsIgnoreCase(b);
Странные задачи, когда нужно считать, что строки "encyclopædia" и "encyclopaedia" равны
a.Equals(b, System.StringComparison.InvariantCulture);
a.Equals(b, System.StringComparison.InvariantCultureIgnoreCase);
???
Странные задачи, когда нужно считать, что строки "encyclopædia" и "encyclopaedia" равны
a.Equals(b, System.StringComparison.CurrentCulture);
a.Equals(b, System.StringComparison.CurrentCultureIgnoreCase);
???

Другие особенности

Работа со временем всегда была головной болью программистов. Занятно почитать, например, историю о человеке, который участвовал в большом распределенном проекте и его мысли о том, что класс Date в Java - это позор)).
Но вернемся к C#.
Из-за того, что сравнение строк - дело темное, это всплывает в неожиданных местах, например:

Неправильно на C# Правильно C# На Java
DateTime.Now.ToString("dd.MM.yyyy");
DateTime.Now.ToString("dd.MM.yyyy", CultureInfo.CurrentCulture);
new SimpleDateFormat("dd.MM.yyyy").format(new Date());
Double.Parse(val);
Double.Parse(val, CultureInfo.CurrentCulture);
Double.parseDouble(val);
string.Format("Hello, {0}", "world!");
string.Format("Hello, {0}", "world!", CultureInfo.CurrentCulture);
String.format("Hello, %s", "world!");

И многое многое другое...

Заключение

Итак, не впадайте в иллюзию, что знание Java автоматически дарует вам глубокое понимание языка C#. 
При всей своей внешней схожести, языки различны по своим ценностным установкам, подходам и т.п.
Там, где Java опирается на комьюнити и сторонние библиотеки, C# будет опираться на богатые возможности языка и экосистему разработки. И нельзя сказать, кто из них двигается единственно верным путем. 
Поэтому учите оба языка программирования (и еще Javascript, конечно), чтобы ваши руки были свободными, мнение непредвзятым, а носки поглаженными).
Удачи!



Комментариев нет:

Отправить комментарий