title: Is String.IndexOf(char) really slower than manual searching?
body: <p>When doing a simple performance measurement, I was astonished to see that calling <code>String.IndexOf(char)</code> was actually slower than doing it manually! Is this really true?! Here is my test code:</p>
  
  <pre><code>const string str = @"91023m lkajsdfl;jkasdf;piou-09324\\adf \asdf\45\ 65u\ 86\ 8\\\;";
  static int testIndexOf() { return str.IndexOf('\\'); }
  static int testManualIndexOf() {
      string s = str;
      for (int i = 0; i &lt; s.Length; ++i)
          if (s[i] == '\\') return i;
      return -1;
  }
  </code></pre>
  
  <p>I ran each method 25 million times, and measured the time using a <code>Stopwatch</code>. The manual version was consistently 25% faster than the other one.</p>
  
  <p>Any thoughts?!</p>
  
  <hr>
  
  <p><strong>Edit 2:</strong> Running the tests on a different machine with .NET 4.0 yields results very similar to those in Marc Gravell's answer. <strong><code>String.IndexOf(char)</code></strong> <em>is faster</em> than manual searching.</p>
  
  <hr>
  
  <p><strong>Edit:</strong> Today (Jan 4 '09) I wanted to check this issue in a more comprehensive way, so I created a new project, and wrote the code you'll find below. I got the following results when running release mode from cmd for 100 million iterations:</p>
  
  <pre><code>  -   String.      IndexOf : 00:00:07.6490042
    - MyString.PublicIndexOf : 00:00:05.6676471
    - MyString.InternIndexOf : 00:00:06.1191796
    - MyString.PublicIndexOf2: 00:00:09.1363687
    - MyString.InternIndexOf2: 00:00:09.1182569
  </code></pre>
  
  <p>I ran these tests at least 20 times, getting almost the same results every time. My machine is XP SP3, VS 2008 SP1, P4 3.0 GHz with no hyper-threading and 1 GB RAM. I find the results really strange. As you can see, <code>String.IndexOf</code> was about 33% slower than my <code>PublicIndexOf</code>. Even stranger, I wrote the same method as <code>internal</code>, and it was about 8% slower than the <code>public</code> one! I do not understand what's happening, and I hope you could help me understand!</p>
  
  <p>The testing code is below. (Sorry for the repeated code, but I found that using a delegate showed different timings, with the <code>public</code> and <code>internal</code> methods taking the same time.)</p>
  
  <pre><code>public static class MyString {
      public static int PublicIndexOf(string str, char value) {
          for (int i = 0; i &lt; str.Length; ++i)
              if (str[i] == value) return i;
          return -1;
      }
  
      internal static int InternIndexOf(string str, char value) {
          for (int i = 0; i &lt; str.Length; ++i)
              if (str[i] == value) return i;
          return -1;
      }
  
      public static int PublicIndexOf2(string str, char value, int startIndex) {
          if (startIndex &lt; 0 || startIndex &gt;= str.Length)
              throw new ArgumentOutOfRangeException("startIndex");
          for (; startIndex &lt; str.Length; ++startIndex)
              if (str[startIndex] == value) return startIndex;
          return -1;
      }
  
      internal static int InternIndexOf2(string str, char value, int startIndex) {
          if (startIndex &lt; 0 || startIndex &gt;= str.Length)
              throw new ArgumentOutOfRangeException("startIndex");
          for (; startIndex &lt; str.Length; ++startIndex)
              if (str[startIndex] == value) return startIndex;
          return -1;
      }
  }
  
  class Program {
      static void Main(string[] args) {
          int iterations = 100 * 1000 * 1000; // 100 millions
          char separator = '\\';
          string str = @"91023m lkajsdfl;jkasdf;piou-09324\\adf \asdf\45\ 65u\ 86\ 8\\\;";
          Stopwatch watch = new Stopwatch();
  
          // test String.IndexOf
          int sum = 0;
          watch.Start();
          for (int i = 0; i &lt; iterations; ++i)
              sum += str.IndexOf(separator);
          watch.Stop();
          Console.WriteLine("  String.      IndexOf : ({0}, {1})", watch.Elapsed, sum);
  
          // test MyString.PublicIndexOf
          sum = 0;
          watch.Reset(); watch.Start();
          for (int i = 0; i &lt; iterations; ++i)
              sum += MyString.PublicIndexOf(str, separator);
          watch.Stop();
          Console.WriteLine("MyString.PublicIndexOf : ({0}, {1})", watch.Elapsed, sum);
  
          // test MyString.InternIndexOf
          sum = 0;
          watch.Reset(); watch.Start();
          for (int i = 0; i &lt; iterations; ++i)
              sum += MyString.InternIndexOf(str, separator);
          watch.Stop();
          Console.WriteLine("MyString.InternIndexOf : ({0}, {1})", watch.Elapsed, sum);
  
          // test MyString.PublicIndexOf2
          sum = 0;
          watch.Reset(); watch.Start();
          for (int i = 0; i &lt; iterations; ++i)
              sum += MyString.PublicIndexOf2(str, separator,0);
          watch.Stop();
          Console.WriteLine("MyString.PublicIndexOf2: ({0}, {1})", watch.Elapsed, sum);
  
          // test MyString.InternIndexOf2
          sum = 0;
          watch.Reset(); watch.Start();
          for (int i = 0; i &lt; iterations; ++i)
              sum += MyString.InternIndexOf2(str, separator,0);
          watch.Stop();
          Console.WriteLine("MyString.InternIndexOf2: ({0}, {1})", watch.Elapsed, sum);
      }
  }
  </code></pre>