title: Why is regex.IsMatch(str) faster than str.EndsWith (invariant culture)?
body: <p>This is some micro-benchmarking for a code path that is traversed a gazillion times per nanosecond and needs to be fast. </p>
  
  <p>For the code snippet below, comparing</p>
  
  <ul>
  <li><code>x.EndsWith(y, InvariantCulture)</code></li>
  <li><code>Regex(y, Compiled | CultureInvariant).IsMatch(x)</code></li>
  </ul>
  
  <p>I get the following figures:</p>
  
  <pre><code>=============================
  Regex   : 00:00:01.2235890. Ignore this: 16666666
  EndsWith: 00:00:03.2194626. Ignore this: 16666666
  =============================
  Regex   : 00:00:01.0979105. Ignore this: 16666666
  EndsWith: 00:00:03.2346031. Ignore this: 16666666
  =============================
  Regex   : 00:00:01.0687845. Ignore this: 16666666
  EndsWith: 00:00:03.3199213. Ignore this: 16666666
  </code></pre>
  
  <p>In other words, <code>EndsWith</code> needs 3 times as much time as <code>Regex</code>.</p>
  
  <p>I should note that I experimented with other values and <strong>depending on the string values used, sometimes <code>EndsWith</code> is faster, sometimes <code>Regex</code> is</strong>.</p>
  
  <p><code>EndsWith(x, InvariantCulture)</code> boils down to some argument checking and then <strike><a href="http://referencesource.microsoft.com/#mscorlib/system/string.cs,97a2816565a71677,references" rel="nofollow"><code>extern int nativeCompareOrdinalEx(String, int, String, int, int)</code></a>, which I'd expect to be fast</strike>. (As @nhahtdh correctly pointed out, in the case of <code>InvariantCulture</code> it calls <code>CultureInfo.InvariantCulture.CompareInfo.IsSuffix which calls InternalFindNLSStringEx</code>. I had accidentally followed the <code>Ordinal</code> trail)</p>
  
  <p><strong>N.B.</strong>: I just found out that when calling EndsWith with <code>Ordinal</code> instead of <code>InvariantCulture</code>, EndsWith gets so much faster than Regex... Unfortunately there's no <code>RegexOptions.Ordinal</code> to compare it with.</p>
  
  <p>I also expected the compiled regular expression to be fast, but how can it beat the specialized method?</p>
  
  <p>Le code:</p>
  
  <pre><code>string[] BunchOfIDs =
  {
      "zxc@x@432143214@O@abcße",
      "zxc@x@432143214@T@abcßX",
      "qwe@x@432143214@O@abcße",
      "qwe@x@432143214@XXabc",
      "zxc@x@1234@O@aXcße",
      "qwe@y@1234@O@aYcße",
  };
  
  var endsWith = "@abcße";
  var endsWithRegex = new Regex("@abcße$", RegexOptions.None);
  
  int reps = 20000000;
  for (int i = 0; i &lt; 3; i++)
  {
      Console.WriteLine("=============================");
      int x = 0;
      var sw = Stopwatch.StartNew();
      for (int j = 0; j &lt; reps; j++)
      {
          x += BunchOfIDs[j % BunchOfIDs.Length].EndsWith(endsWith, StringComparison.InvariantCulture) ? 1 : 2;
      }
      Console.WriteLine("EndsWith: " + sw.Elapsed + ". Ignore this: " + x);
  
      x = 0;
      sw = Stopwatch.StartNew();
      for (int j = 0; j &lt; reps; j++)
      {
          x += endsWithRegex.IsMatch(BunchOfIDs[j % BunchOfIDs.Length]) ? 1 : 2;
      }
      Console.WriteLine("Regex   : " + sw.Elapsed + ". Ignore this: " + x);
  }
  </code></pre>