Pull to refresh

Незаконченная история перехода с Delphi на C#

Reading time10 min
Views38K

Предисловие


Всем доброго времени суток. Начиная с 2003 года, и по сегодняшний день, я профессионально занимаюсь разработкой прикладного программного обеспечения в среде Delphi 7 — Delphi 2010. И надо сказать, что эта работа позволяет мне достаточно неплохо зарабатывать на хлеб и пользоваться уважением своих коллег в нескольких организациях, с которыми я работаю.
Но многие наверняка знают о трудностях компании Borland, и как следствие провальной судьбе нескольких, вышедших подряд, версиях Delphi. Все Delphi, начиная с версии 8 (~2003 год) по 2007-ю, были не просто непопулярны. Их IDE были крайне нестабильны. Фатальные сбои среды разработки, требующие перезапуска, становились неотъемлемой частью процесса программирования. Сам язык менялся настолько незначительно, что большинство разработчиков на вопрос: “Что изменилось в новой версии?” могли только невнятно пробубнить: “Ну,… кажется, были добавлены новые компоненты…”. И только в 2009 году отделившаяся от Borland компания CodeGear смогла вывести на рынок относительно стабильную RAD Studio 2009, включающую новую версию Delphi. Подведя итоги, получаем 6 с лишним лет застоя, на фоне бурно развивающихся информационных технологий.
Поэтому и по сей день, значительный процент профессиональных разработчиков Delphi работает в 7-й версии. Могу только посочувствовать их упорству и посоветовать (если они и далее желают работать с Delphi) как можно скорее осваивать Delphi 2010. В сравнении с Delphi 7, 2010-я версия — это качественный скачек вперед. Я не стану подробно останавливаться на сравнении, поскольку это расходиться с темой статьи, но совсем промолчать не могу. Таких людей нужно чаще мотивировать, поскольку привыкание может быть существенной помехой на пути профессионального развития. Перейдя на версию 2010, вы получите стабильно работающую IDE, значительно превосходящую по комфорту работы среду Delphi 7. Из языковых возможностей вы приобретете поддержку юникода, возможность работы с обобщенными типами и анонимные методы, которые также могут плодотворно сказаться на качестве кода и скорости работы.

Начало


Многие из вас знают о том, какие жаркие дискуссии вызывают темы типа Firefox vs Opera, iOS vs Anrdoid, Intel vs AMD, ATI vs NVidia, Oracle vs MsSql и т.д. И, подчас, кажется, что такие дискуссии крайне бесполезны и даже деструктивны: накал страстей зашкаливает, людям трудно удержаться от оскорблений и перехода на личности, а толку ноль, все остаются при своем мнении. В мире программирования такие обсуждения тоже не редкость. Вспомните: Java vs C#, Delphi vs C++, HTML 5 vs Silverlight, Perl vs Python.
Начиная примерно с 2003 года, после выхода Visual Studio 2003 не затихали споры Delphi vs C#. Надо сказать, что программистам Delphi всегда удавалось дать достойный отпор своим оппонентам. С 2006-го года я ушел с головой в работу и почти перестал посещать форумы, и тем более участвовать в подобных спорах. По-моему, осенью 2009 года я оторвался от очередного проекта и с удивлением для себя обнаружил, что в спорах между разработчиками Delphi и C# уверенную победу одерживают последние. Программистам Delphi уже практически нечего было противопоставить нововведениям Visual Studio и C#. И даже с выходом Delphi 2009 ситуация не изменилась, а только усугубилась. На замечания, что в Delphi 2009 добавлена поддержка юникода, сторонники C# могли ответить: «Не прошло и 10 лет. C# поддерживает юникод с самой первой версии». С чьей-то легкой руки Embarcadero стали называть “быдлокадеро”, и многие Delphi программисты стали писать, что переходят на C++, Java или C#.
Было и еще пару моментов, которые сподвигли меня вплотную заняться изучением C#. Первый из них произошел в 2009 году, когда меня отправили на курсы по Delphi 2009. На этих курсах преподаватель и просто умнейший человек Волков Владимир Борисович с грустью отмечал, как компания Microsoft фактически задавила Borland, и что .NET Framework уже содержит гораздо более богатый набор классов, нежели модули и компоненты Delphi.
Вторым моментом была информация о том, что над архитектурой C# трудится Андерс Хейлсберг, который был главным архитектором компании Borland и руководил работой по переводу Turbo Pascal в объектно-ориентированный язык разработки object Pascal (впоследствии Delphi). Этот человек был движущей силой развития Delphi и, возможно, без него разработчики Delphi уже столько лет топчутся на месте. Думаю, что в архитектуре C# он смог реализовать все то, что хотел вложить в развитие Delphi, но не смог из-за политики и финансовых проблем компании Borland.

Изучение C#


Возможно благодаря общему архитектору двух языков Андерсу Хейлсбергу, для меня, как программиста Delphi, не составило особых сложностей изучить C#. Думаю, что немаловажную роль тут сыграло и то, что изучение C# я начал с прочтения книги Эндрю Троелсена «Язык программирования C# 2008 и платформа. NET 3.0». Доступность и подробность изложения делает эту книгу очень хорошей стартовой платформой для подготовки C# программиста.
Здесь хочу сделать небольшое отступление, и рассказать, что Delphi в свое время я больше изучал на практических примерах во время работы, спрашивая советы более опытных коллег и задавая вопросы на форумах. И сейчас понимаю, что для более плодотворной работы мне не хватало хорошей теоретической основы. Моей большой ошибкой было то, что я поленился закупить качественную литературу и подробно изучить несколько книг по Delphi. Это позволило бы мне овладеть языком как минимум в пару раз быстрее. Кстати говоря, сейчас, если попробуете поискать книги по Delphi то практически ничего не найдете. Разве что Осипова, цены, на книги которого упали до 50 рублей за 1000 страничную книгу, просто потому, что их никто не покупает.
Совершенно другая картина складывается в области C#, Visual Studio и .NET. Литературы огромное количество на любой вкус. Есть и очень качественные книги, которые не сложно отыскать среди общего изобилия по отзывам читателей. Назову еще несколько книг, которые позволили мне ознакомиться и в достаточной мере овладеть C# и окружающими ее технологиями:
  • Г. Шилдт. C# 3.0 Руководство для начинающих.
  • Г. Шилдт. C# 3.0 Полное руководство.
  • Мак-Дональд. WPF: Windows Presentation Foundation в. NET 3.0 для профессионалов.
  • Мак-Дональд. Silverlight 2 с примерами на C# 2008 для профессионалов.
  • Трей Неш. C# 2010 ускоренный курс для профессионалов.
  • Албахари. LINQ. Карманный справочник.
  • Арсеновски. Рефакторинг в C# и ASP. NET для профессионалов.

Я читал их именно в этом порядке, после прочтения Троелсена. Некоторые параллельно дома и на работе. Стараясь понять каждый пример, повторяя после прочтения ключевые изученные моменты. Были и другие книги, но в список я включил только прочитанные и понравившиеся. В них заложен хороший теоретический фундамент, позволяющий мне сейчас решать задачи на C# быстро и эффективно, даже в сравнении со скоростью моей работы на Delphi. И это не смотря на то, что с Delphi я работаю уже более 8-ми лет, и этот язык является основным на моем текущем месте работы, а C# я вплотную занялся менее полутора лет назад.
Г. Шилдт дает хорошие базовые знания пространств имен и классов .NET Framework. Мак-Дональд раскрывает суть нового подхода Microsoft к формированию пользовательского интерфейса посредством языка разметки XAML, практически универсальной как для Windows, так и для Web приложений.
Книга Трея Неша произвела на меня пожалуй самое сильное впечатление благодаря высокому уровню мастерства автора. Он даст вам знания в области функционального программирования в C#, опишет пути и уровни синхронизации многопоточного приложения, заложит основы написания безопасного кода. Думаю, что профессионалы, прочитав его книгу, смогут подняться на пару ступенек выше. Но ее нужно читать, имея за плечами хорошую подготовку по C#.
Книга Албахари поможет вам в деталях ознакомиться с новым, появившимся в версии C# 3.0, языком интегрированных запросов LINQ. Его знания позволят вам с наименьшими усилиями извлекать нужную информацию из массивов, коллекций, XML документов и БД (в основном MsSQL, но благодаря Entity Framework перечень поддерживаемых БД может быть расширен).
Арсеновски раскрывает модную сейчас тему рефакторинга. Но в отличие от других авторов в его книге упор делается на специфике языка C#, а также использовании особенностей языка и среды Visual Studio для реализации приемов рефакторинга. Все примеры приведены на языке C#.
О книгах можно много говорить. И здесь на хабре мне попадались статьи о пользе чтения для профессионального развития. Я же только хочу призвать тех, кто берется за изучение новой для него области набраться терпения, выбрать и купить несколько книг на заданную тему, и ежедневно как минимум полчаса в день уделять чтению и изучению. Для себя я выбрал такую стратегию. Если книга, которую я читаю, достаточно сложна, то я читаю ее по 10 страниц в день, разбавляя ее более легкой литературой (типа бестселлера “Джоэл о программировании”). В противном случае стараюсь читать специальной литературы не менее 20 страниц в день. При таком подходе практически ни одна книга не залежится у вас более 2-х месяцев, а, как правило, она будет прочитана еще быстрее.

Чего мне не хватает в C# и Visual Studio


Вплотную поработав с двумя языками и двумя средами программирования, и сделав для себя четкий выбор в пользу C# и Visual Studio, я естественно стал замечать некоторые особенности языка и IDE, которые в Delphi меня устраивали больше. Это примерно такое же чувство, как если четыре года подряд прокататься на одном велосипеде, который в принципе тебя почти всем устраивал, а потом купить и пересесть на новый, более современный, с дисковыми гидравлическими тормозами, облегченной рамой, 27-ю скоростями и прочими наворотами. Почти сразу станут видны нюансы, которые на старом велосипеде были реализованы лучше: сидение не так впивается в энное место, нога лучше сидит на педали, ручки руля не так натирают руки и т.д.
Итак. Перечень того, что мне не хватает в C# и Visual Studio в сравнении с Delphi и RAD Studio:

Проверка на попадание во множество

В Delphi есть возможность произвести проверку на попадание числа (в пределах одного байта, т.е. о 0 до 255), или ANSI символа во множество, примерно таким образом:
  1. procedure CheckID;
  2. var
  3.  id: byte;
  4.  
  5.  function GetID: byte;
  6.  begin
  7.   result := Random(256);
  8.  end;
  9.  
  10. begin
  11.  id := GetID;
  12.  if id in [37..75,100] then // <-проверка попадания числа во множество
  13.   ShowMessage('Повезло, выпал номер: ' + IntToStr(id));
  14. end;

Необходимо отметить, что помимо удобства, такая проверка выполняется крайне быстро и эффективно, так как связана с битовыми операциями.
В C# аналогичная проверка связана с гораздо более существенным объемом кодирования. Вот один из вариантов:
  1.     private void CheckID()
  2.     {
  3.       HashSet<byte> set = new HashSet<byte>(new byte[] {100});
  4.       for (byte i = 37; i <= 75; i++)
  5.         set.Add(i);
  6.  
  7.       byte id = GetID();
  8.  
  9.       if (set.Contains(id))
  10.         MessageBox.Show("Повезло, выпал номер: " + id);
  11.     }
  12.  
  13.     private byte GetID()
  14.     {
  15.       Random random = new Random();
  16.       return (byte)random.Next(256);
  17.     }

Вполне возможно, что кто-то сможет предложить более простой вариант на C#, но это то лучшее, что пока смог придумать я. На создание множества, которое задается в Delphi 12-символами “[37..75,100]”, в C# уходит 3 строки кода, включающие создание объекта и цикл.

Вложенные функции

В Delphi есть возможность реализовать методы, имеющие уровень видимости, не выходящий за пределы метода, в котором они реализованы (чтобы название “метод” не коробило Delphi программистов, поясню, что то, что в C# называется методами, в Delphi называется процедурами и функциями). Функция GetID из предыдущего примера как раз такая. И это крайне удобно, поскольку не загромождает класс методами, которые используются только внутри одного другого метода. В C# можно искусственно реализовать что-то подобное благодаря делегатам, но смотрится такой вариант не так элегантно, как в Delphi, поскольку создание делегата является частью тела метода:
  1.     private void CheckID()
  2.     {
  3.       Func<byte> getID = () =>
  4.       {
  5.         Random random = new Random();
  6.         return (byte)random.Next(256);
  7.       };
  8.  
  9.       HashSet<byte> set = new HashSet<byte>(new byte[] {100});
  10.       for (byte i = 37; i <= 75; i++)
  11.         set.Add(i);
  12.  
  13.       byte id = getID();
  14.  
  15.       if (set.Contains(id))
  16.         MessageBox.Show("Повезло, выпал номер: " + id);
  17.     }


Явное приведение типов

Это достаточно мелкое замечание, но пару раз я с ним сталкивался, и необходимость дополнительных скобок вызывала смех у стоящих у меня за спиной Delphi программистов. Итак, явное приведение, на примере преобразования ссылки на класс в ссылку на его дочерний подкласс. Вариант C#:
  1.   class Employee
  2.   {
  3.   }
  4.  
  5.   class Manager : Employee
  6.   {
  7.     public byte GetBonus()
  8.     {
  9.       return 5;
  10.     }
  11.   }
  12. //…..
  13.     private void ShowManagerBonus()
  14.     {
  15.       Employee manager = new Manager();
  16.       MessageBox.Show("Бонус составляет: " + ((Manager)manager).GetBonus());
  17.     }

Обратите внимание на наличие двойной открывающей скобки перед именем класса Manager. В Delphi такое приведение типов выглядит так:
  1. Manager(manager).GetBonus;
Сравните с вариантом на C#:
  1. ((Manager)manager).GetBonus();

На мой взгляд, способ Delphi намного более элегантен. Только не нужно говорить, что в C# можно воспользоваться оператором as. Это ничего не меняет, поскольку в Delphi также есть такая возможность.

TStringList

В Delphi есть замечательный класс TStringList, существенно облегчающий работу с коллекциями строк и текстовыми файлами. Аналогов ему нет ни в многочисленных потоках (типа StringReader, StreamReader) C#, ни в классе StringBuilder.
Предположим, стоит задача добавить в файл C:\1.txt первой строкой фразу: “Доброго времени суток!”. В Delphi это можно реализовать следующим образом:
  1. procedure ChangeFile;
  2. const
  3.  fileName = 'C:\1.txt';
  4. var
  5.  stringList: TStringList;
  6. begin
  7.  try
  8.   stringList := TStringList.Create;
  9.   stringList.LoadFromFile(fileName);
  10.   stringList.Insert(0, 'Доброго времени суток!');
  11.   stringList.SaveToFile(fileName);
  12.  finally
  13.   FreeAndNil(stringList);
  14.  end;
  15. end;

Попробуйте реализовать то же самое на C#. Если у Вас получится сделать это также элегантно, то я буду только рад, поскольку давно уже ищу такой способ.

Чтение данных с электронной почты

Буквально около месяца назад столкнулся с тем, что в .NET Framework отсутствуют классы для работы с электронной почтой через протоколы POP и IMAP. Пришлось искать бесплатные библиотеки в поисковиках. Но к моему разочарованию ничего, кроме вот этого достаточно старого проекта я не нашел. Позже на форуме MSDN мне посоветовали попробовать еще одну бесплатную библиотеку. Но факт остается фактом. Задача работы с электронной почтой не из редких, а в .NET нужных классов .НЕТ. В Delphi, уже много лет есть пакет Indy, в котором реализован нужный функционал.

Закладки в модулях кода

Конечно, я сейчас не скажу, что в Visual Studio нет возможности добавлять закладки. Все дело в том, что в RAD Studio их добавление и переход по ним реализован на порядок удобнее: Shift + Ctrl + цифра устанавливает нужную закладку в модуле, а комбинация Ctrl + цифра позволяет на нее перейти. Все настолько просто и интуитивно понятно, что нет необходимости в дополнительных окнах с кнопками и списками закладок. Если закладка с каким-то номером Вам стала не нужна, вы просто переопределяете ее той же самой комбинацией клавиш. Я был очень сильно удивлен, когда не нашел ничего подобного в Visual Studio. Если я плохо искал и такая возможность есть, буду только рад услышать критику в свой адрес, поскольку в итоге еще одним неудобством в работе для меня станет меньше.

Поиск в модуле кода

Ну, и напоследок еще одно замечание. Опять же не могу сказать, что поиск в модуле кода в Visual Studio не реализован. Я даже не могу сказать, что он реализован неудобно. Он просто реализован не так удобно, как в Delphi, начиная с версии 2009. В RAD Studio при нажатии Ctrl + f не появляется никакого дополнительного окна, а появляется небольшая панель в нижней части экрана с полем, в которое можно ввести строку поиска. После нажатия клавиши Enter редактор кода не просто переходит на искомый участок кода, все вхождения искомой строки также четко выделяются в коде. Благодаря стрелкам «Следующий» и «Предыдущий» можно в любой момент продолжить поиск в прямом или обратном направлении.
image

Может это просто моя привычка заставляет меня думать, что в Delphi поиск реализован удобнее? Но посмотрите, например, реализацию поиска в самом популярном на сегодня интернет браузере firefox и увидите почти аналогичную реализацию.

Еще раз поясню, что в этом разделе я вовсе не пытался доказать превосходство Delphi. Для меня лично, превосходство C# очевидно. Я хотел показать те нюансы, которых мне недостает во время работы с C#.

Заключение


В нашей бурно развивающейся отрасли нельзя не следить за изменениями. Если бы полтора года назад я не оторвал голову от работы, то мог бы и до сих пор не замечать, что перспективы Delphi программистов неуклонно падают. Попробуйте поискать вакансии по Delphi и C#, попробуйте поискать книги по Delphi и C#. А затем сравните их количество. Сложного математического анализа не нужно, чтобы увидеть разницу. Надеюсь, это статья поможет куму-то сделать правильный выбор. В моих планах разрабатывать новые проекты на C# и с использованием технологий, окружающих этот язык программирования. Но как говорят: «Если хочешь рассмешить Бога, расскажи ему о своих планах».
Tags:
Hubs:
+46
Comments226

Articles

Change theme settings