String.Contains() follows a torturous route through System.Globalization.CompareInfo into the CLR and the NLS support sub-system where I thoroughly got lost. This contains highly optimized code with impressive perf. The only way to do it faster is through pinvoking the standard CRT function wcsstr, available in msvcrt.dll
[DllImport("msvcrt.dll", CharSet = CharSet.Unicode)]
private static extern IntPtr wcsstr(string toSearch, string toFind);
It returns IntPtr.Zero if the string wasn't found. I made some measurements, using String.IndexOf() instead of Contains() to test the various string comparison options. All times are in nanoseconds, searching for a string of 7 characters in a string of 60 characters. With the string not present so worst case is measured. The lowest time out of a sample of 20 was used:
StringComparison.Ordinal (same as Contains) : 245 nanoseconds
StringComparison.OrdinalIgnoreCase : 327
StringComparison.InvariantCulture : 251
StringComparison.InvariantCultureIgnoreCase : 327
StringComparison.CurrentCulture : 275
StringComparison.CurrentCultureIgnoreCase : 340
wcsstr : 213
Very impressive numbers and on par with what you'd expect these functions to require. The wcsstr() function does the same kind of ordinal comparison as String.Compare(). It is only 13% faster, a statistically insignificant improvement given that real perf is not likely to approach these measurements due to the effects of CPU cache locality. I can only conclude that you're going about as fast as you can expect. Whether the slight improvement from wcsstr is worth it is up to you.