Вопрос о рефакторинге C#

Я приехал через следующий код сегодня, и мне не нравился он. Довольно очевидно, что это делает, но я добавлю немного объяснения здесь так или иначе:

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

Я посмотрел на него и думал, что это было немного ужасно - мне не нравятся операторы переключения, и я ненавижу вещи, которые продолжают выполнять итерации через список, после того как они закончены. Таким образом, я решил осуществить рефакторинг его.

Мой вопрос всем Вам состоит в том, как Вы осуществили бы рефакторинг его? Или Вы думаете, что этому даже нужен рефакторинг вообще?

Вот код:

        using (var sqlConnection = new SqlConnection(Lfepa.Itrs.Framework.Configuration.ConnectionString))
        {
            sqlConnection.Open();

            var dataTable = new DataTable("Settings");

            var selectCommand = new SqlCommand(Lfepa.Itrs.Data.Database.Commands.dbo.SettingsSelAll, sqlConnection);
            var reader = selectCommand.ExecuteReader();
            while (reader.Read())
            {
                switch (reader[SettingKeyColumnName].ToString().ToUpper())
                {
                    case DatabaseVersionKey:
                        DatabaseVersion = new Version(reader[SettingValueColumneName].ToString());
                        break;
                    case ApplicationVersionKey: 
                        ApplicationVersion = new Version(reader[SettingValueColumneName].ToString());
                        break;
                    default:
                        break;
                }
            }

            if (DatabaseVersion == null)
                throw new ApplicationException("Colud not load Database Version Setting from the database.");
            if (ApplicationVersion == null)
                throw new ApplicationException("Colud not load Application Version Setting from the database.");
        }
11
задан james lewis 11 June 2010 в 12:17
поделиться

8 ответов

Мои два цента...

  1. Как заметил Bobby, используйте using на каждом одноразовом объекте
  2. Я бы не стал открывать таблицу и перебирать все записи, используйте фильтр, если возможно, для получения значений
  3. Если это невозможно, избегайте использования switch на строках, так как есть только два варианта, как вы можете сделать if else со строкой.Сравните с вариантом без учета регистра, чтобы не делать верхний каждый раз.
  4. Проверяйте нулевые значения перед их чтением, чтобы избежать необработанных исключений
  5. Если в коде вам приходится открывать подобные соединения много раз, вы можете использовать фабричный метод для создания соединения.
  6. Я бы избегал использования ключевого слова "var", когда вы уже знаете, какой объект вы создаете. Обычно вы проводите рефакторинг, чтобы улучшить читаемость кода.
16
ответ дан 3 December 2019 в 05:56
поделиться

В коде есть небольшие неэффективности (много выделений строк и ненужных поисков).

Вот код с некоторыми изменениями:

  • Нет вызова ToUpper(). (ToUpper и ToLower могут быть злыми )
  • кэширование значения DataReader
  • отсутствие вызовов ToString
  • удалено создание экземпляра DataTable (не используется)

Получившийся код выглядит так:

using (var sqlConnection = new SqlConnection(Lfepa.Itrs.Framework.Configuration.ConnectionString))
{
    sqlConnection.Open();

    using(var selectCommand = new SqlCommand(Lfepa.Itrs.Data.Database.Commands.dbo.SettingsSelAll, sqlConnection))
    {
        using (var reader = selectCommand.ExecuteReader())
        {
            while (reader.Read())
            {
                string val = reader.GetString(reader.GetOrdinal(SettingKeyColumnName));
                if ( string.IsNullOrEmpty(val) )
                    continue;
                if ( val.Equals(DatabaseVersionKey, StringComparison.OrdinalIgnoreCase))
                    DatabaseVersion = new Version(val);
                else if (val.Equals(ApplicationVersionKey, StringComparison.OrdinalIgnoreCase))
                    ApplicationVersion = new Version(val);
            }
        }
    }
}

if (DatabaseVersion == null)
    throw new ApplicationException("Could not load Database Version Setting from the database.");
if (ApplicationVersion == null)
    throw new ApplicationException("Could not load Application Version Setting from the database.");
2
ответ дан 3 December 2019 в 05:56
поделиться

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

1
ответ дан 3 December 2019 в 05:56
поделиться

Этот код на самом деле выполняет две разные функции:

1) Get the database version

2) Get the application version

Единственное общее - это метод хранения данных

Я бы предложил для рефакторинга три метода:

// Get the entire dataset from the database using the SettingsSelAll command.
private DataTable GetVersionData() {...}
// Parse a version from the dataset.
private Version GetVersion(string versionName, DataTable dataSet) { ... }

public Version GetVersion(string versionName)
{
    DataTable table = GetVersionData();
    return GetVersion(versionName, table);
}

Это обеспечивает разделение между получением data и фактически что-то с ними делать, что всегда является целью. Было бы рекомендовано использовать кеширование, чтобы не выполнять запрос дважды, и я бы предложил, возможно, иметь метод, который выполнял бы как вызовы версии базы данных, так и версии приложения за один шаг.

1
ответ дан 3 December 2019 в 05:56
поделиться

Я бы переписал запрос так, чтобы он возвращал одну запись с двумя столбцами. Это позволило бы избавиться от условий внутри оператора using(). Как сказал Гейб, я бы добавил

if (DatabaseVersion != null && ApplicationVersion != null) break;

внутри блока using.

0
ответ дан 3 December 2019 в 05:56
поделиться

используйте if вместо переключателя менее чем для 5 случаев, это быстрее.

0
ответ дан 3 December 2019 в 05:56
поделиться

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

0
ответ дан 3 December 2019 в 05:56
поделиться

Одно из предложений, которое я бы добавил, это выполнить проверку, чтобы убедиться, что соединение с базой данных было установлено перед выполнением дальнейших команд.

sqlConn.Open();

if (sqlConn.State == ConnectionState.Open)
{

   // perform read settings logic here

}
0
ответ дан 3 December 2019 в 05:56
поделиться
Другие вопросы по тегам:

Похожие вопросы: