Рефакторинг кода в Visual Studio

77

Существует много способов вызвать инструменты для рефакторинга в системе Visual Studio 2013, включая контекстное меню, которое открывается после щелчка правой кнопкой мыши, интеллектуальные дескрипторы и меню Refactor в главном меню (только для разработчиков, работающих на языке программирования C#).

На рисунке ниже показано контекстное меню Refactor, предназначенное для разработчиков, работающих на языке программирования C#. Полный список действий по рефакторингу, доступных для разработчиков C# в системе Visual Studio 2013, включает операции Rename, Extract Method, Encapsulate Field, Extract Interface, Remove Parameters и Reorder Parameters. Можно также использовать операции Generate Method Stub и Organize Usings, которые с некоторой натяжкой также можно отнести к рефакторингу.

Операции рефакторинга кода, доступные в Visual Studio

Встроенная поддержка рефакторинга, предлагаемая системой Visual Studio 2013 для разработчиков проектов на языке VB, ограничена символическими методами Rename и Generate Method Stub.

Операции рефакторинга

В следующих разделах описывается каждая из операций рефакторинга и приводятся примеры использования встроенной поддержки рефакторинга в языках C# и VB.

Операция Extract Method

Чтобы начать рефакторинг длинного метода, лучше всего разбить его на несколько небольших частей. Для этого необходимо выделить область кода, которую разработчик хочет удалить из исходного метода, и выбрать команду Extract Method из контекстного меню. В языке C# это приведет к появлению приглашения ввести имя нового метода, как показано на рисунке ниже. Если в удаляемом блоке кода есть переменные, которые использовались ранее, они автоматически становятся переменными в сигнатуре нового метода. После подтверждения имени нового метода его код вставляется сразу после исходного метода. Удаленный блок метода заменяется вызовом нового метода.

Создание метода с помощью рефакторинга

Например, в следующем сниппете, для того чтобы вынести условное логическое выражение в отдельный метод, необходимо выделить код и выбрать команду Extract Method из контекстного меню, появляющегося после щелчке правой кнопкой мыши:


   private void button1_Click(object sender, EventArgs e)
{
    string connectionString = Properties.Settings.Default.ConnectionString;
    
    // Выделите текст с этого места
    if (connectionString == null)
    {
         connectionString = "DefaultConnectionString";
    }
    // до сюда, и вызовите команду Extract Method
    
    MessageBox.Show(connectionString);
    /* ... Продолжение длинного метода ... */
}

На этом месте автоматически генерируется следующий код:

private void button1_Click(object sender, EventArgs e)
{
    string connectionString = Properties.Settings.Default.ConnectionString;
    
    connectionString = ValidateConnectionString(output);
    
    MessageBox.Show(connectionString);
    /* ... Продолжение длинного метода ... */
}

private static string ValidateConnectionString(string connectionString)
{
    if (connectionString == null)
    {
        connectionString = "DefaultConnectionString";
    }
    
    return connectionString;
}

Операция Encapsulate Field

При рефакторинге часто требуется инкапсулировать в существующий класс некое свойство. Для этого предназначена операция Encapsulate Field. Чтобы выполнить это действие, следует выбрать переменную, которую требуется инкапсулировать, и выбрать соответствующую команду в контекстном меню. Это дает разработчику возможность указать свойство и выбрать место, в котором следует искать ссылку на него:

Пример использовании операции рефакторинга Encapsulate Field

На следующем шаге после указания нового свойства следует определить, какие ссылки на переменную класса следует заменить ссылкой на новое свойство. Откроется окно предварительного просмотра по завершении поиска ссылок. В верхней панели окна размещено дерево, в котором указываются поля и методы, имеющие ссылки на данную переменную. Флажок, расположенный после каждой строки, указывает, следует ли выполнять замену. Выбрав строку в верхней части окна, необходимо установить на нее фокус в нижней панели. Как только будет обеспечена корректность каждой ссылки, инкапсуляция считается завершенной. Переменная класса устанавливается закрытой, а соответствующие ссылки обновляются.

Операция Extract Interface

По мере того как проект проходит этапы развития от прототипа на ранней стадии разработки до полной реализации или стадии роста, часто возникает необходимость выделить основные методы в виде интерфейса, доступного другим приложениям, или определить границы между непересекающимися системами. Прежде для этого приходилось копировать весь метод в новый файл и удалять его содержимое, оставляя лишь заглушку интерфейса. Операция рефакторинга Extract Interface позволяет извлечь интерфейс, используя любое количество методов в классе. При выполнении этой операции открывается диалоговое окно, показанное на рисунке ниже, которое позволяет пользователю выбрать метод, который он хочет включить в интерфейс. После того как разработчик сделает выбор, эти методы добавляются в новый интерфейс. Кроме того, новый интерфейс добавляется в исходный класс.

Извлечение интерфейса с помощью команды рефакторинга Extract Interface

В следующем примере требуется извлечь в отдельный интерфейс первый метод:

public class ConcreteClass
{
    public void ShouldBeInInterface()
    { /* ... */ }
    
    public void AnotherNormalMethod(int ParameterA, int ParameterB)
    { /* ... */ }
    
    public void NormalMethod()
    { /* ... */ }
}

После выбора команды Extract Interface из контекстного меню, появляющегося после щелчка правой кнопкой мыши, и выбора метода ShouldBeInInterface, подлежащего извлечению, в диалоговом окне Extract Interface (как показано на рисунке выше), в новом файле возникает новый интерфейс, а исходный файл обновляется следующим образом:

interface IBestPractice
{
	void ShouldBeInInterface();
}

public class ConcreteClass: Chapter08Sample.IBestPractice
{
    public void ShouldBeInInterface()
    { /* ... */ }
    
    public void NormalMethod(int ParameterA, int ParameterB)
    { /* ... */ }
    
    public void AnotherNormalMethod()
    { /* ... */ }
}

Операция Reorder Parameters

Иногда требуется переупорядочить параметры. Часто это делают по "косметическим" причинам, но эта операция может помочь повысить читабельность и иногда является необходимой при реализации интерфейсов.

Диалоговое окно Reorder Parameters dialog, показанное на рисунке ниже, позволяет переставлять параметры в списке в соответствии с требуемым порядком:

Перестановка параметров метода с помощью команды рефакторинга Reorder Parameters

Как только требуемый порядок будет достигнут, пользователь может предварительно просмотреть результат. По умолчанию параметры в каждом вызове данного метода переставляются автоматически в соответствии с новым порядком. Диалоговое окно Preview, аналогичное показанному на рисунке, позволяет контролировать обновление вызовов метода.

Операция Remove Parameters

Удаление параметра из метода с помощью соответствующей операции рефакторинга значительно сокращает объем поиска ошибок компиляции, которые могут при этом возникнуть. Кроме того, эта операция очень полезна при многочисленных перегрузках метода, при которых удаление параметра не может порождать ошибки компиляции. В этом случае ошибка во время выполнения программы может возникнуть только по семантической, а не по синтаксической причине.

На рисунке ниже показано диалоговое окно Remove Parameters, которое используется для удаления параметров из списка параметров. Если параметр был удален непреднамеренно, его легко восстановить. Как указывает предупреждение, размещенное в этом диалоговом окне, удаление параметров часто приводит к неожиданным функциональным ошибкам, поэтому важно контролировать внесенные изменения. Для того чтобы оценить внесенные изменения, можно снова использовать окно предварительного просмотра.

Использование команды рефакторинга Remove Parameters

Операция Rename

Система Visual Studio 2013 обеспечивает переименование переменных, методов и классов как в языке C#, так и в языке VB. Диалоговое окно Rename для языка C# приведено на рисунке ниже; оно довольно похоже на соответствующее окно для языка VB, хотя в нем нет функции поиска комментариев или строк.

Переименование переменных с помощью операции рефакторинга Rename

В отличие от поддержки переименования переменных в языке предусматривающей использование окна предварительного просмотра, в котором можно было подтвердить внесенные изменения, функции переименования в языке VB просто переименовывают все ссылки на данную переменную.

Операция Generate Method Stub

Когда разработчик пишет код, он может прийти к выводу, что ему нужен вызов метода, который еще не написан. Например, следующий сниппет иллюстрирует новый метод, который должен быть сгенерирован на более поздней стадии:

public void MethodA()
{
	string InputA;
	double InputB;
	int OutputC = NewMethodIJustThoughtOf(InputA, InputB);
}

Разумеется, этот код порождает ошибку при сборке, поскольку вызываемый метод еще не определен. Используя операцию рефакторинга Generate Method Stub (доступную с помощью интеллектуального указателя в самом коде), можно сгенерировать заглушку метода. Как видно из следующего примера, заглушка метода содержит входные параметры и тип возвращаемого значения:

private int NewMethodIJustThoughtOf(string InputA, double InputB)
{
	throw new Exception("The method or operation is not implemented.");
}

Меню Organize Usings

Очень полезно поддерживать упорядоченный список директив using в каждом файле (на языке C#) и ссылаться только на те пространства имен, которые действительно необходимы в данном файле. Команда Organize Usings, доступная в контекстном меню, которое открывается после щелчка пользователем правой кнопкой мыши в окне редактора кода, поможет в обоих этих случаях:

Использование команд меню Organize Usings

После рефакторинга кода может выясниться, что в начале файла содержится множество директив using, которые больше не используются. Чтобы определить, какие из этих директив используются, а какие нет, вместо метода проб и ошибок можно выполнить операцию, предусмотренную системой Visual Studio. Для этого достаточно щелкнуть правой кнопкой мыши в окне редактора кода и выбрать команду Organize Usings --> Remove Unused Usings (в языке C#). Неиспользуемые директивы using, их альтернативные имена и внешние альтернативные имена сборок из исходного файла будут удалены.

Разработчики проектов на языке VB не имеют возможности упорядочивать и удалять неиспользуемые инструкции Imports. Однако на закладке References в диалоговом окне Project Properties можно пометить пространства имен, которые должны быть импортированы в каждый исходный файл. Это позволит значительно сократить количество инструкций Imports. На этой странице можно также удалить ссылки на неиспользуемые сборки.

Очень полезно упорядочивать директивы using в алфавитном порядке, чтобы легко управлять пространствами имен, на которые они ссылаются. Для того чтобы не делать это вручную, нужно щелкнуть правой кнопкой мыши в окне редактора кода и выбрать команду Organize Usings --> Sort Usings.

Если для пространству имен задано альтернативное имя, то оно переносится в конец списка, а если в проекте используются альтернативные имена внешних сборок (с помощью ключевого слова extern в языке C#), то они перемещаются в начало списка.

Для того чтобы одновременно упорядочить директивы using и удалить неиспользуемые, достаточно щелкнуть правой кнопкой мыши в окне редактора кода и выбрать команду Organize Usings --> Remove and Sort.

Файлы шаблонного кода, предусмотренные в системе Visual Studio по умолчанию, содержат директивы using в начале файла за пределами блока пространства имен. Однако, согласно принципам стиля StyleCop, директивы using должны содержаться в блоке пространства имен. Операция Organize Usings распознает текущее расположение инструкций using в файле и оставляет их на месте.

Пройди тесты
Лучший чат для C# программистов