Есть ли какой-то выигрыш в производительности с «цепочкой» операторов в .NET? - PullRequest
3 голосов
/ 20 сентября 2008

При получении значения кода поиска из таблицы некоторые люди делают это ...

Dim dtLookupCode As New LookupCodeDataTable()
Dim taLookupCode AS New LookupCodeTableAdapter()
Dim strDescription As String

dtLookupCode = taLookupCode.GetDataByCodeAndValue("EmpStatus", "FULL")
strDescription = dtLookupCode.Item(0).Meaning

... тем не менее, я также видел, как что-то вроде "приковано" ...

strDescription = taLookupCode.GetDataByCodeAndValue("EmpStatus", "FULL").Item(0).Meaning

... что в первую очередь обходит наличие таблицы данных кода поиска, поскольку адаптер таблицы знает, как выглядит структура его набора результатов.

Сохраняет ли использование метода "chained" накладные расходы на создание объекта таблицы данных или он все равно эффективно создается для правильной обработки оператора .Item (0) .Meaning?

Ответы [ 11 ]

5 голосов
/ 20 сентября 2008

Эти две строки будут скомпилированы в одно и то же. Я бы выбрал тот, который легче читать. Под вставкой обычно понимается что-то немного другое .

4 голосов
/ 20 сентября 2008

В отличие от «встроенной» части этого, два набора кода не будут компилироваться в одно и то же. Проблема приходит с:

Dim dtLookupCode As New LookupCodeDataTable()
Dim taLookupCode AS New LookupCodeTableAdapter()

В VB это создаст новые объекты с соответствующими именами ссылок. Вслед за:

dtLookupCode = taLookupCode.GetDataByCodeAndValue("EmpStatus", "FULL")

Мы немедленно заменяем исходную ссылку dtLookupCode новым объектом, который создает мусор для сбора (недоступный объект в ОЗУ).

Следовательно, в точном, оригинальном сценарии то, что называется «встроенной» техникой, является технически , более производительным. (Однако вряд ли вы физически увидите эту разницу в этом небольшом примере.)

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

Dim taLookupCode AS New LookupCodeTableAdapter
Dim dtLookupCode As LookupCodeDataTable
Dim strDescription As String

dtLookupCode = taLookupCode.GetDataByCodeAndValue("EmpStatus", "FULL")
strDescription = dtLookupCode.Item(0).Meaning

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

Dim taLookupCode AS New LookupCodeTableAdapter
Dim dtLookupCode As LookupCodeDataTable = taLookupCode.GetDataByCodeAndValue("EmpStatus", "FULL")
Dim strDescription As String = dtLookupCode.Item(0).Meaning
2 голосов
/ 20 сентября 2008

Обычно это делает код менее читабельным.

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

Вот две иллюстрации. Следует избегать первого фрагмента:

if (ConfigurationManager.AppSettings("ConnectionString") == null)
{
    throw new MissingConfigSettingException("ConnectionString");
}

string connectionString = ConfigurationManager.AppSettings("ConnectionString");

Второе предпочтительнее:

string connectionString = ConfigurationManager.AppSettings("ConnectionString")

if (connectionString == null)
{
    throw new MissingConfigSettingException("ConnectionString");
}

Проблема здесь в том, что AppSettings () фактически должна распаковывать коллекцию AppSettings каждый раз, когда извлекается значение:

// Disassembled AppSettings member of ConfigurationManager 

public static NameValueCollection AppSettings
{
    get
    {
        object section = GetSection("appSettings");

        if ((section == null) || !(section is NameValueCollection))
        {
            throw new
                ConfigurationErrorsException(SR.GetString("Config_appsettings_declaration_invalid"));
        }

        return (NameValueCollection) section;
    }
}
2 голосов
/ 20 сентября 2008

Да, не говорите «inline», потому что это означает что-то конкретное в других языках. Скорее всего, разница в производительности равна нулю или настолько мала, что не имеет значения, это просто вопрос предпочтений. Вы хотите записать его в отдельных выражениях, чтобы сделать его более понятным, или записать все в одну строку, чтобы быстрее его набрать?

1 голос
/ 20 сентября 2008

Одной из причин «сцепления» является * закон Деметры , который предполагает, что ваш код хрупок перед лицом изменений в LookupCodeDataTable.

Вы должны добавить такую ​​функцию:

function getMeaning( lookupCode as LookupCodeDataTable)
 getMeaning=lookupCode.Item(0).Meaning
end function

и назовите это так:

strDescription=getMeaning(taLookupCode.GetDataByCodeAndValue("EmpStatus", "FULL"))

Теперь getMeaning () доступен для вызова во многих других местах, и если LookupCodeDataTable изменится, вам нужно всего лишь изменить getMeaning (), чтобы исправить это.

1 голос
/ 20 сентября 2008

Я называю это цепочкой.

Вы задаете неправильный вопрос.

Что вам нужно спросить: что более читабельно?

Если создание цепочек делает код более легким для чтения и понимания, чем идти вперед и делать это.

Если, однако, это запутывает, то не надо.

Любые оптимизации производительности не существуют. Не оптимизируйте код, оптимизируйте алгоритмы.

Таким образом, если вы собираетесь вызывать Item (1) и Item (2), то при объединении в цепочку вы будете снова и снова создавать один и тот же объект, что является плохим алгоритмом.

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

1 голос
/ 20 сентября 2008

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

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

0 голосов
/ 10 декабря 2009

Помимо удобства обслуживания, есть еще одна причина, по которой следует избегать цепочки: проверка ошибок.

Да, вы можете обернуть все это в try / catch и поймать каждое исключение, которое может вывести любая часть .

Но если вы хотите проверить результаты между вызовами без try / catch, вы должны разделить вещи на части. Например:

  • Что происходит, когда GetDataByCodeAndValue возвращает ноль?
  • Что если он вернет пустой список?

Вы не можете проверить эти значения без try / catch, если вы цепочки.

0 голосов
/ 20 сентября 2008

То же самое, если вам не нужно ссылаться на возвращенные объекты taLookupCode.GetDataByCodeAndValue ("EmpStatus", "FULL") или Item (0) многократно. В противном случае вы не знаете, является ли время выполнения этой функции log (n) или n, поэтому для лучшей ставки я бы назначил ссылку на нее.

0 голосов
/ 20 сентября 2008

Это:

dtLookupCode = taLookupCode.GetDataByCodeAndValue("EmpStatus", "FULL")
strDescription = dtLookupCode.Item(0).Meaning

и это:

strDescription = taLookupCode.GetDataByCodeAndValue("EmpStatus", "FULL").Item(0).Meaning

полностью эквивалентны.

В первом примере у вас есть явная временная ссылка (dtLookupTable). Во втором примере временная ссылка неявная. За кулисами компилятор почти наверняка создаст один и тот же код для них обоих. Даже если он не не выдал тот же код, дополнительная временная ссылка будет чрезвычайно дешевой.

Однако я не уверен, что эта строка:

Dim dtLookupCode As New LookupCodeDataTable()

эффективен. Мне кажется, что это создает новый LookupCodeDataTable, который затем отбрасывается при перезаписи переменной в последующем операторе. Я не программирую на VB, но я ожидаю, что эта строка должна быть:

Dim dtLookupCode As LookupCodeDataTable

Ссылка дешевая (возможно, бесплатная), но создание дополнительной справочной таблицы может не быть.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...