Подтвердить что ты не робот

Является String.Equals(string1.Substring(0, x), string2) лучше, чем string1.StartsWith(string2)?

Я использую сравнения строк для проверки URL-адресов с помощью StringComparison.OrdinalIgnoreCase.

MSDN дает следующий совет по сравнению с текстом ЗДЕСЬ, но не уточняет ПОЧЕМУ:

Пример MSDN (на полпути вниз по приведенной выше странице):

public static bool IsFileURI(string path) 
{
   path.StartsWith("FILE:", StringComparison.OrdinalIgnoreCase);
   return true;
}

Совет MSDN:

"Однако в предыдущем примере используется метод String.StartsWith(String, StringComparison) для проверки равенства. Поскольку целью сравнения является проверка равенства, а не упорядочение строк, лучшей альтернативой является вызов Equals метод, как показано в следующем примере."

public static bool IsFileURI(string path)
{
   if (path.Length < 5) return false;

   return String.Equals(path.Substring(0, 5), "FILE:", 
                    StringComparison.OrdinalIgnoreCase);
}

ВОПРОС: Почему MSDN предлагает второй пример лучше?

Точки обсуждения:

  • Очевидно, что return true; в первом примере является ошибкой и должен быть return path.StartsWith(...);. Мы можем смело игнорировать это как ошибку, так как правильный код VB.

  • Создание подстроки перед сравнением для равенства, по-видимому, будет использовать только другой ресурс памяти, чем просто вызов String.StartsWith().

  • Длина < 5 - хорошее короткое замыкание, однако его можно использовать с прежним кодом точно так же.

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

4b9b3361

Ответ 1

Рассматривая метод StartsWith, используя dotPeek, он в конечном итоге вызывает внутреннюю функцию сравнения, которая сравнивает всю строку и возвращает логический результат на основе возвращаемого значения этого сравнения:

return TextInfo.CompareOrdinalIgnoreCaseEx(this, 0, value, 0, value.Length, value.Length) == 0;

String.Equals вызывает:

return TextInfo.CompareOrdinalIgnoreCase(this, value) == 0;

CompareOrdinalIgnoreCase вызывает частный метод, который dotPeek не показывает, но моя догадка заключается в том, что перегрузка, вызываемая StartsWith, пересекает всю строку, а перегрузка, вызываемая Equals, останавливается, как только может быть определено равенство.

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


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

using System;
using System.Diagnostics;

namespace ConsoleApplication1
{
    internal class Program
    {
        private static void Main(string[] args)
        {
            var url = "http://stackoverflow.com/questions/8867710/is-string-equalsstring1-substring0-x-string2-better-than-string1-startswit";
            var count = 10000000;
            var http = false;

            Stopwatch sw = Stopwatch.StartNew();

            for (int i = 0; i < count; i++)
            {
                http = url.StartsWith("http:", StringComparison.OrdinalIgnoreCase);
            }

            sw.Stop();

            Console.WriteLine("StartsWith: {0} ms", sw.ElapsedMilliseconds);

            sw.Restart();

            for (int i = 0; i < count; i++)
            {
                http = string.Equals(url.Substring(0, 5), "http:", StringComparison.OrdinalIgnoreCase);
            }

            sw.Stop();

            Console.WriteLine("Equals: {0} ms", sw.ElapsedMilliseconds);

            Console.ReadLine();
        }
    }
}

Ответ 2

Ответ найден непосредственно ниже примера кода, представленного в разделе Ordinal String Operations.

Строки в .NET Framework могут содержать встроенные нулевые символы. Одно из самых явных различий между порядковыми и культурно-чувствительными сравнение (включая сравнения, в которых используется инвариантная культура) относится к обработке встроенных нулевых символов в строке. Эти символы игнорируются при использовании String.Compare и Методы String.Equals для проведения культурно-чувствительных сравнений (включая сравнения, в которых используется инвариантная культура). В результате, в чувствительных к культуре сопоставлениях, строки, содержащие встроенный нуль символы можно считать равными строкам, которые этого не делают.

Важно

Несмотря на то, что методы сравнения строк не учитывают встроенный нуль символы, строковые методы поиска, такие как String.Contains, String.EndsWith, String.IndexOf, String.LastIndexOf и String.StartsWith нет.

Значение, что String.StartsWith и String.Equals, которые используют порядковые сравнения, возвращают разные результаты. То есть весь смысл использования порядковых сравнений состоял в том, чтобы предотвратить людей в турецких системах, которые обошли проблемы безопасности (где "f" != "F" при игнорировании дела). Понятно, что кто-то все еще мог обойти проблемы безопасности, передав URI файла, который выглядел как "FIL\0E:", если в используемом тесте String.StartsWith