Вот и настал тот переломный момент, когда мы решили перевести два проекта с VB на С#. Кому интересно — прошу под кат.
Введение
Данные проекты нам достались от подрядческой организации, которая писала их на протяжении лет 5-6. В общей сложности это около 1,5 млн. строк кода, если верить средству оценки метрик в Visual Studio, из которых около 30% на C#, а остальное на VB. Почему мы решили это сделать?! Скорее всего из-за нежелания работать с VB и отсутствия хороших vb-разработчиков.
Сроки, которые поставило наше руководство на полный перевод проектов, неумолимо стремились к чему-то близкому с нулем, коллеги, из подрядческой организации, тоже спешили расстаться с этими проектами и вздохнуть с облегчением. Отложив все не срочные дела, посидев на паре совещаний, мы приступили к реализации данной идеи.
Подготовка
Любое дело начинается именно с этого. Даже при лимите во времени и золотых руках, бросаться сразу в бой не следует, также поступили и мы.
В силу специфичных различий языков, необходимо предварительно подготовить проект для конвертации. Мы выделили несколько этапов, после которых будет, относительно безболезненно, проходить процесс конвертации.
Почему относительно?! Да потому, что после конвертации, в любом случае, имеется нотка неизвестного поведения программы. Это может всплыть сразу, если у вас код не покрыт 100% тестами. В нашем случае, я про тесты вообще промолчу, ибо нет их вовсе. Ну что ж – рассмотрим, что за шаги мы выделили:
1) Выбор инструмента для конвертации
Это очень важный этап на таком нелегком пути, ведь от того какую пилу выберешь, будет зависеть скорость и качество распила. После многочисленных вопросов гуглу и совещаний, мы остановились на двух продуктах: Instant CSharp и SharpDevelop версии 4.х (в версии 5.х конвертация не поддерживается), что очень странное, на мой взгляд, решение.
SharpDevelop бесплатен – это несомненно плюс, но и Instant CSharp имеет free версию, которая не отличается функциональностью от платной версии, лишь имеется ограничение на число строк в конвертируемом проекте. Плюсом Instant CSharp является то, что он лучше конвертирует WinForms. Есть у него и минус – это корректная конвертация только UTF файлов.
Решили использовать Instant CSharp для мелких проектов, а SharpDevelop для всего остального.
2) Составление списка VB проектов и формирование диаграммы зависимостей
Этот шаг необходим, чтобы наглядно понять с какой-же стороны начать работу. Приведу пример одной из диаграмм зависимостей, которая у нас получилась:
На данной диаграмме также указано число зависимостей между проектами. Из диаграммы, да и по логике вещей, видно, что порядок преобразования проектов — от проектов с меньшим количеством зависимостей к проектам с большим количеством зависимостей.
3) Замена ReDim на Array.Resize()
Был написан небольшой класс Re, чтобы реализовать данную замену.
Public Class Re
Public Shared Sub [Dim](Of T)(ByRef Source As T(), HighBound As Integer)
//изменяем размер массива
DimPreserve(Source, HighBound)
//очищаем массив
Array.Clear(Source, 0, HighBound + 1)
End Sub
Public Shared Sub DimPreserve(Of T)(ByRef Source As T(), HighBound As Integer)
//изменяем размер массива
Array.Resize(Source, HighBound + 1)
End Sub
End Class
Далее все вызовы ReDim Preserve X(N) заменили на Re.DimPreserve(X,N), а ReDim X(N) заменили на Re.Dim(X,N).
4) Включение опции компиляции strict
По умолчанию .NET Visual Basic или компилятор Visual Basic не обеспечивает строгую типизацию. Чтобы изменить это поведение по умолчанию, необходимо в свойствах проекта на вкладке Compile установить Option strict в значение on. После этого исправить все возникшие ошибки.
Следующие пункты не требуют разъяснений, так как они просты и понятны. Мы просто берем в руки ReSharper и выполняем все, описанные ниже пункты, со скоростью звука (а то и еще быстрее).
5) Для value type переменных заменить Nothing на Default
6) Замена And на AndAlso и Or на OrElse
7) Удаление конструкций Imports, ссылающихся на классы
8) Замена вызова метода вида .Method на .Method()
9) Удаление конструкций Exit Try
10) Замена сравнения строковых переменных с Nothing или "" или со String.Empty на String.IsNullOrEmpty()
11) Замена ненужных директив ByRef на ByVal у параметров методов
12) Переименование методов, имеющих имя своего же класса
13) Исправление некорректных регистронезависимых вызовов в VB коде
Конвертация
И вот мы подошли к завершающему этапу – этапу конвертации. Инструмент выбран, проекты подготовлены и ждут своей участи.
Что ж – начнем!
Процесс конвертации не сложнее программы «Hello World», только требует немного большего времени. Приведу небольшой tutorial, как это делается в SharpDevelop и Instant CSharp.
2. Открыть проект в SharpDevelop (File->Open->Project/Solution)
3. Сконвертировать проект (Project->Convert->From VB.NET to C#)
4. Открыть в Visual Studio основной солюшен и удалить проект VB.NET
5. Удалить папку с проектом VB.NET
6. Переименовать папку и файл сконвертированного в C# проекта (убрать слово Converted)
7. Скопировать папку с новым проектом в каталог с основным солюшеном
8. Добавить в солюшен скопированный проект
9. Добавить ссылки на новый проект (C#) во все остальный проекты, в которых были ссылки на старый (VB.NET). Для этого можно воспользоваться средством системы управления версиями для просмотра изменений в файлах *.csproj и *.vbproj
10. Попробовать скомпилировать проект. Исправить возникающие ошибки
2. В поле Source directory указать путь к каталогу проекта
3. В поле Target directory указать путь к каталогу в который будут перемещены файлы проекта в кодировке UTF8
4. Выстовить опцию Copy unconverted и запустить преобразование
И после этих танцев с бубном можно производить конвертацию проекта.
1. Открыть Instant CSharp
2. В поле VB project or solution: указать путь к файлу проекта *.vbproj
3. В поле C# target folder: указать каталог, в который будет сохранён сконвертированный в C# проект
4. Сконвертировать проект (Project->Convert->From VB.NET to C#)
5. Открыть в Visual Studio основной солюшен и удалить проект VB.NET
6. Удалить папку с проектом VB.NET
7. Скопировать папку с новым проектом в каталог с основным солюшеном
8. Добавить в солюшен скопированный проект
9. Добавить ссылки на новый проект (C#) во все остальный проекты, в которых были ссылки на старый (VB.NET). Для этого можно воспользоваться средством системы управления версиями для просмотра изменений в файлах *.csproj и *.vbproj
10. Попробовать скомпилировать проект. Исправить возникающие ошибки
Вывод
В итоге мы перевели оба наших проекта полностью на c#.Сейчас идет, полным ходом, рефакторинг кода, кстати, не в рекламу будет сказано, но ReSharper в этом деле не заменим. В процессе эксплуатации, иногда, всплывают ошибки, связанные с конвертацией, но это неизбежно, увы.
Надеюсь, наш небольшой опыт будет полезен и вам, уважаемые читатели.
Ссылки
Автор: Hell31