В 53 выпуске подкаста DotNet & More ( сайт , YouTube ) мы обсудили возможности C# 10 и рассмотрели их применимость в будущем.
И только тогда возник вопрос: все ли конструкции языка из C# 1, 2, 3, 4 и т.д. мы применим? И даже если они ужасно устарели, есть ли ситуации, в которых их можно использовать?
Говоря о C#, я бы разделил его жизненный путь на 2 вехи: до C#6 и начиная с C#6. Именно с выпуском шестой версии Microsoft изменила свой подход к проектированию языка и стала активно прислушиваться к мнению сообщества.
Именно поэтому я хотел затронуть не столько «современный» C#, сколько C# 2012 года, который многие программисты «старой школы» считают True C# (а поскольку этим ребятам уже 30+ лет, они занимают позиции командного лиды и продакт-менеджеры соответственно определяют технологический стек проекта).
Если посмотреть на C# 5 с точки зрения ненужных возможностей, то их будет не так много.
На мой взгляд, я бы отметил следующее:
- Делегированный оператор: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/delegate-operator
- Динамический тип: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/reference-types#the-dynamic-type
- Выражение запроса: https://docs.microsoft.com/en-us/dotnet/csharp/linq/query-expression-basics
Оператор делегата
То, что этот оператор беззастенчиво устарел, подтверждают сами Microsoft в своей справке:Но внутренний манчкин не терпит такой траты ключевых слов.
Действительно ли лямбда-выражения во всех отношениях лучше такого «лампового» делегата? Нет, есть одна особенность: в операторе делегата мы можем опускать параметры метода, если они нам не нужны.
В лямбда-выражениях можно использовать подчеркивание (_), но если у функции много параметров, то код, который вы получите, будет неприятен с эстетической точки зрения.
Давайте сравним:
противFunc<int, string, double, User, bool> allowAll = (_, _, _, _) => true;
Func<int, string, double, User, bool> allowAll = delegate { return true; };
Этот пример, честно говоря, очень вдохновляет. Ведь мы нашли применение такому «динозавру»! Конечно, я бы не рискнул использовать такой подход в реальных проектах: эстетика есть эстетика, но разочарование других разработчиков такими синтаксическими конструкциями может стоить не один человеко-час.
И мне бы не хотелось тратить время команды.
Динамический тип
Ни для кого не секрет, что динамический тип был добавлен в C# для облегчения работы с COM (см.https://stackoverflow.com/questions/14098958/c-sharp-dynamic-com-objects ).
Конечно, кто-то скажет, что разработчики решили порадовать программистов и превратить C# в такой красивый и удивительный язык, как JavaScript, но давайте будем честны сами с собой, в 2010 году Microsoft пошла по пути Балмера с построением собственной закрытой экосистемы, уделяя минимальное внимание мир.
И поэтому не стоит сбрасывать со счетов динамику, COM жив, и будет жить, пока жив MS Office. Иногда вам также приходится использовать динамический режим при работе с библиотеками, использующими эту возможность, например, ASP Net MVC. Однако я бы не сказал, что такая практика вообще широко распространена.
Но если вы не разрабатываете надстройки для Excel, есть ли смысл использовать динамические типы? На самом деле да: динамический тип чрезвычайно удобен для прототипирования.
Когда мысль летит вперед, переход к DTO-файлу с полями просто прервет ее.
dynamic entity = new ExpandoObject();
// the genius code with 'entity' variable
Такой подход чрезвычайно удобен при обсуждении реализации и «выкидывании» вариантов решения задачи: вместо рисования на доске можно сразу написать примерный вариант решения в коде и, более того, запустить это решение.
В противном случае придется признать, что динамика — это огромный кусок ненужной функциональности.
И это очень печально, ведь сочетание статической и динамической типизации может стать невероятно мощным инструментом.
На мой взгляд, этого не произошло потому, что была потеряна одна из важнейших особенностей языков программирования, таких как JavaScript и Python: интерпретируемость.
Хотя среда выполнения динамического языка имеет интерпретацию, у нас нет возможности избежать перекомпиляции сборки, а это означает, что мы не можем вносить изменения во время работы приложения.
Например, разработчики 1С очень часто пишут код инкрементно — код вводится в обработчик нажатия кнопок по мере прохождения интерпретатора, поэтому для какого-либо мелкого исправления нет необходимости перезапускать приложение.
В C# вам придется компенсировать это подходом Test First.
Выражение запроса
Этот синтаксический сахар вызвал много споров 10 лет назад, и это хорошо видно в коде, написанном в те времена, но сегодня всем совершенно очевидно, что код похож на var teenagers = from u in users
where u.Age is > 10 and < 18
select u.Name;
гораздо сложнее с точки зрения расширяемости и поддержки, чем «точечная запись».
var teenagers = users
.
Where(u => u.Age is > 10 and < 18) .
Select(u => u.Name);
Однако есть по крайней мере один случай, когда выражение запроса наносит ответный удар: работа с несколькими SelectManys. Давайте представим, что мы хотим найти друзей нашего пользователя.
Запишем в разных обозначениях: private IEnumerable<User> GetFriends(string myName) =>
_users
.
Where(u => u.Name == myName) .
SelectMany(u => u.Friends);
private IEnumerable<User> GetFriends(string myName) =>
from u in _users
where u.Name == myName
from f in u.Friends
select f;
В этом случае Dot Notation определенно лучше, по крайней мере, по количеству строк.
Что делать, если нам нужно запросить друзей друзей? private IEnumerable<User> GetFriendsOfFriends(string myName) =>
_users
.
Where(us => us.Name == myName) .
SelectMany(u =>
u.Friends.SelectMany(f => f.Friends)
);
private IEnumerable<User> GetFriendsOfFriends(string myName) =>
from u in _users
where u.Name == myName
from f in u.Friends
from fof in f.Friends
select fof;
Здесь ситуация гораздо интереснее, поскольку в первом случае избежать вложенности не удается.
И это может стать довольно серьезной проблемой в случае действительно больших запросов, например, если вам нужно найти не просто друзей друзей, а друзей друзей друзей друзей: private IEnumerable<User> GetFriendsOfFriendsOfFriendsOfFriendsOfFriends(string myName) =>
_users
.
Where(us => us.Name == myName) .
SelectMany(u =>
u.Friends.SelectMany(f =>
f.Friends.SelectMany(fof =>
fof.Friends.SelectMany(fofof =>
fofof.Friends.SelectMany(fofofof => fofofof.Friends)
)
)
)
);
private IEnumerable<User> GetFriendsOfFriendsOfFriendsOfFriendsOfFriends(string myName) =>
from u in _users
where u.Name == myName
from f in u.Friends
from fof in f.Friends
from fofof in fof.Friends
from fofofof in fofof.Friends
from fofofofof in fofofof.Friends
select fof;
Конечно, этот пример немного надуман, но в кровавом предприятии так не бывает. Главное, что в C# есть инструмент «выпрямления» вложенности LINQ и в ряде случаев он просто незаменим.
P.S.: Также можно отметить, что использовать Join гораздо удобнее в виде Query Expression, чем в Dot Notation, но на мой взгляд, все зависит от привычки.
Заключение
Будем честны, приведенные примеры — это, по сути, стрельба по воробьям из пушки.Нет смысла тратить время на изучение этих устаревших синтаксических конструкций просто потому, что в некоторых случаях они будут немного полезны.
И даже если вы мастер Query Expression, эксперт DLR и не представляете своей жизни без делегата, не стоит усложнять жизнь коллегам.
Но все же не с прагматической, а с романтической точки зрения приятно осознавать, какую мощь содержит в себе C#, какие богатые возможности, позволяющие выражать свои мысли более кратко и ясно.
Теги: #C++ #.
NET #LINQ #делегат #dlr
-
Sitereviewsauthority И Что Это Такое
19 Oct, 24 -
Как Начать Зарабатывать Деньги В Интернете
19 Oct, 24 -
К Черту Провода
19 Oct, 24 -
Linux С Материальным Дизайном
19 Oct, 24 -
Тестирование Storekit В Xcode 12 И Ios 14
19 Oct, 24 -
Стелька-Генератор
19 Oct, 24