Your current implementation could be more efficient. Copying the passed in string and chopping it up is probably pretty expensive (I'm not a master of .NET internals though).
val.Count()
Why not val.Length? Count() is very inefficient compared to Length.
copy = copy.Remove(indexOfVal, val.Count());
We don't need to remove part of the string, just search again starting at indexOfVal + val.Length.
Here is an example using an overload of String.IndexOf:
public static int Occurences(this string str, string val)
{
int occurrences = 0;
int startingIndex = 0;
while ((startingIndex = str.IndexOf(val, startingIndex)) >= 0)
{
++occurrences;
++startingIndex;
}
return occurrences;
}
This implementation will count overlapping occurrences (so "bbb".Occurences("bb") will return 2.
If you don't want to count overlapping occurences, you can replace ++startingIndex; with:
startingIndex += val.Length
On why an exception isn't thrown in the case of "foo".Occurrences("o"), from MSDN:
If startIndex equals the length of the string instance, the method returns -1.