После прочтения этой темы я провел небольшой эксперимент, который дал два отличных и интересных вывода.
Рассмотрим следующее.
strInstallString "1" string
Вышеупомянутое скопировано из локального окна отладчика Visual Studio. Одно и то же значение используется во всех трех следующих примерах.
if (strInstallString == "") === if (strInstallString == string.Empty)
Ниже приведен код, отображаемый в окне разборки отладчика Visual Studio 2013 для этих двух принципиально идентичных случаев.
if ( strInstallString == "" )
003126FB mov edx,dword ptr ds:[31B2184h]
00312701 mov ecx,dword ptr [ebp-50h]
00312704 call 59DEC0B0 ; On return, EAX = 0x00000000.
00312709 mov dword ptr [ebp-9Ch],eax
0031270F cmp dword ptr [ebp-9Ch],0
00312716 sete al
00312719 movzx eax,al
0031271C mov dword ptr [ebp-64h],eax
0031271F cmp dword ptr [ebp-64h],0
00312723 jne 00312750
if ( strInstallString == string.Empty )
00452443 mov edx,dword ptr ds:[3282184h]
00452449 mov ecx,dword ptr [ebp-50h]
0045244C call 59DEC0B0 ; On return, EAX = 0x00000000.
00452451 mov dword ptr [ebp-9Ch],eax
00452457 cmp dword ptr [ebp-9Ch],0
0045245E sete al
00452461 movzx eax,al
00452464 mov dword ptr [ebp-64h],eax
00452467 cmp dword ptr [ebp-64h],0
0045246B jne 00452498
if (strInstallString == string.Empty) существенно не отличается
if ( strInstallString.Length == 0 )
003E284B mov ecx,dword ptr [ebp-50h]
003E284E cmp dword ptr [ecx],ecx
003E2850 call 5ACBC87E ; On return, EAX = 0x00000001.
003E2855 mov dword ptr [ebp-9Ch],eax
003E285B cmp dword ptr [ebp-9Ch],0
003E2862 setne al
003E2865 movzx eax,al
003E2868 mov dword ptr [ebp-64h],eax
003E286B cmp dword ptr [ebp-64h],0
003E286F jne 003E289C
Из приведенных выше списков машинного кода, сгенерированных модулем NGEN .NET Framework версии 4.5, я делаю следующие выводы.
Проверка на равенство пустого строкового литерала и статической строки. Свойство Empty класса System.string для всех практических целей идентично. Единственное различие между двумя фрагментами кода - это источник первой команды перемещения, и оба являются смещениями относительно ds, что подразумевает, что оба относятся к запеченным константам.
Проверка на равенство с пустой строкой, как литералом, так и свойством string.Empty, устанавливает вызов функции с двумя аргументами, который указывает неравенство , возвращая ноль. Я основываю этот вывод на других тестах, которые я выполнил пару месяцев назад, в которых я следовал некоторым собственным кодам через управляемое / неуправляемое разделение и обратно. Во всех случаях при любом вызове, требующем двух или более аргументов, первый аргумент помещается в регистр ECX, а второй - в регистр EDX. Я не помню, как были переданы последующие аргументы. Тем не менее, настройка вызова была больше похожа на __fastcall, чем __stdcall. Аналогично, ожидаемые возвращаемые значения всегда отображаются в регистре EAX, который является почти универсальным.
Проверка длины строки устанавливает вызов функции с одним аргументом, который возвращает 1 (в регистре EAX), что соответствует длине тестируемой строки.
Учитывая, что машинный код, видимый сразу же, почти идентичен, единственная причина, по которой я могу себе представить, объясняет лучшую производительность равенства строк по длине строки, сообщаемого Shinny , заключается в том, что функция с двумя аргументами, которая выполняет сравнение, значительно лучше оптимизирована, чем функция с одним аргументом, которая считывает длину из экземпляра строки.
Заключение
В принципе, я избегаю сравнения с пустой строкой как литералом, потому что литерал пустой строки может выглядеть неоднозначно в исходном коде. Для этого мои вспомогательные классы .NET давно определили пустую строку как константу. Хотя я использую string.Empty для прямых, встроенных сравнений, константа зарабатывает свое время для определения других констант, значением которых является пустая строка, потому что константе нельзя присвоить string.Empty как его значение.
Это упражнение раз и навсегда решает любую проблему, которую у меня может возникнуть, относительно стоимости, если таковая имеется, сравнения с string.Empty или константой, определенной моими вспомогательными классами.
Однако, это также поднимает загадочный вопрос, чтобы заменить его; почему сравнение с string.Empty более эффективно, чем проверка длины строки? Или тест, используемый Шинни, признан недействительным из-за того, как реализован цикл? (Мне трудно в это поверить, но, опять же, я был одурачен раньше, как, я уверен, и вы тоже!)
Я давно предполагал, что system.string объекты были подсчитаны как строки, которые в основном похожи на давно установленную Basic String (BSTR), которую мы давно знаем из COM.