title: Why doesn't String.Contains call the final overload directly?
body: <p>The <a href="http://msdn.microsoft.com/en-us/library/dy85x1sa%28v=vs.110%29.aspx" rel="nofollow noreferrer">String.Contains</a> method looks like this internally</p>
  
  <pre><code>public bool Contains(string value)
  {
     return this.IndexOf(value, StringComparison.Ordinal) &gt;= 0;
  }
  </code></pre>
  
  <p>The <code>IndexOf</code> overload that is called looks like this</p>
  
  <pre><code>public int IndexOf(string value, StringComparison comparisonType)
  {
     return this.IndexOf(value, 0, this.Length, comparisonType);
  }
  </code></pre>
  
  <p>Here another call is made to the final overload, which then calls the relevant <code>CompareInfo.IndexOf</code> method, with the signature</p>
  
  <pre><code>public int IndexOf(string value, int startIndex, int count, StringComparison comparisonType)
  </code></pre>
  
  <p>Therefore, calling the final overload would be the fastest (albeit may be considered a micro optimization in most cases). </p>
  
  <p>I may be missing something obvious but why does the <code>Contains</code> method not call the final overload directly considering that no other work is done in the intermediate call and that the same information is available at both stages?</p>
  
  <p>Is the only advantage that if the signature of the final overload changes, only one change needs to be made (that of the intermediate method), or is there more to the design than that?</p>
  
  <p><strong>Edit from the comments (see update 2 for speed difference explanation)</strong></p>
  
  <p>To clarify the performance differences I'm getting in case I've made a mistake somewhere:
  I ran <a href="https://stackoverflow.com/a/17579471/187697">this benchmark</a> (looped 5 times to avoid jitter bias) and used this extension method to compare against the <code>String.Contains</code> method</p>
  
  <pre><code>public static bool QuickContains(this string input, string value)
  {
     return input.IndexOf(value, 0, input.Length, StringComparison.OrdinalIgnoreCase) &gt;= 0;
  }
  </code></pre>
  
  <p>with the  loop looking like this </p>
  
  <pre><code>for (int i = 0; i &lt; 1000000; i++)
  {
     bool containsStringRegEx = testString.QuickContains("STRING");
  }
  sw.Stop();
  Console.WriteLine("QuickContains: " + sw.ElapsedMilliseconds);
  </code></pre>
  
  <p>In the benchmark test, <code>QuickContains</code> seems about 50% faster than <code>String.Contains</code> on my machine.</p>
  
  <p><strong>Update 2 (performance difference explained)</strong> </p>
  
  <p>I've spotted something unfair in the benchmark which explains a lot. The benchmark itself was to measure case-insensitive strings but since <code>String.Contains</code> can only perform case-sensitive searches, the <code>ToUpper</code> method was included. This would skew the results, not in terms of final output, but at least in terms of simply measuring <code>String.Contains</code> performance in non case-sensitive searches.</p>
  
  <p>So now, if I use this extension method</p>
  
  <pre><code>public static bool QuickContains(this string input, string value)
  {
     return input.IndexOf(value, 0, input.Length, StringComparison.Ordinal) &gt;= 0;
  }
  </code></pre>
  
  <p>use <code>StringComparison.Ordinal</code> in the 2 overload <code>IndexOf</code> call and remove <code>ToUpper</code>, the <code>QuickContains</code> method actually becomes the slowest. <code>IndexOf</code> and <code>Contains</code> are pretty much on par in terms of performance. So clearly it was the <code>ToUpper</code> call skewing the results of why there was such a discrepancy between <code>Contains</code> and <code>IndexOf</code>. </p>
  
  <p>Not sure why the <code>QuickContains</code> extension method has become the slowest. (Possibly related to the fact that <code>Contains</code> has the <code>[__DynamicallyInvokable, TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries")]</code> attribute?).</p>
  
  <p>Question still remains as to why the 4 overload method isn't called directly but it seems performance isn't impacted (as Adrian and delnan pointed out in the comments) by the decision.</p>