C# - String IndexOf方法,第二个参数等于String length

时间:2017-01-31 14:11:14

标签: c# .net

在我的代码中的某些时候,我使用这种方法:

IndexOf(string str, int startIndex)

我之前也在进行一些计算,并且我使用第二个参数(startIndex)调用此方法,该参数等于作为第一个参数传递的字符串的长度。 当然,字符串中不存在这样的索引,如果我们做了类似的事情:

string[string.Length] 

我们会得到IndexOutOfRangeException

该方法如何正常工作?在MSDN文档中明确指出,startIndex是字符串从零开始的索引。它是否有效并且不会抛出,因为String类操作的char数组是以null结尾的? 我想确保我的程序不会在任何时候抛出。

4 个答案:

答案 0 :(得分:5)

documentation中明确提到:

  

索引编号从0开始.startIndex参数的范围是   0到字符串实例的长度。 如果startIndex等于   字符串实例的长度,方法返回-1

答案 1 :(得分:3)

To the source!

public unsafe int IndexOf(char value, int startIndex, int count) {
    if (startIndex < 0 || startIndex > Length)
        throw new ArgumentOutOfRangeException(nameof(startIndex), Environment.GetResourceString("ArgumentOutOfRange_Index"));

    if (count < 0 || count > Length - startIndex)
        throw new ArgumentOutOfRangeException(nameof(count), Environment.GetResourceString("ArgumentOutOfRange_Count"));

    fixed (char* pChars = &m_firstChar)
    {
        char* pCh = pChars + startIndex;

        while (count >= 4)
        {
            // .. some search
        }

        while (count > 0)
        {
            // .. some search
        }
    }

    return -1;
}

如您所见,ArgumentOutOfRangeException仅在使用比字符串长度更大startIndex时才会被抛出。由于你自己传递长度,这不是问题。如果你要传递一个大于它的数字,你会看到例外:

Console.WriteLine("foo".IndexOf('a', 3)); // -1
Console.WriteLine("foo".IndexOf('a', 4)); // throws ArgumentOutOfRangeException

现在,我们实际上并未调用上面显示的IndexOf。相反,我们称之为以下签名:

public int IndexOf(char value, int startIndex) {
    return IndexOf(value, startIndex, this.Length - startIndex);
}

因此,对于上面的count参数,传递值this.Length - startIndex。由于startIndex等于长度,count将为零。

因此,我们在上面的实现中看到的两个while循环根本不会执行。因此,返回默认结果-1

(小注意:我使用的是.NET Core源代码,因为.NET Framework reference source不包含此方法的来源。虽然实现应该大致相同。)

至于为什么你可以在字符串结束后开始搜索,我有一个简单的解释可能是原因。如果你看一个字符串,你可以开始在多个点搜索。我们使用"foo bar"作为字符串:

Index:        0 1 2 3 4 5 6
Character:    f o o   b a r
Points:      ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑
             0 1 2 3 4 5 6 7

正如您所看到的,对于长度为7的字符串,在字符之前或之后有8个点。当您指定诸如起始索引之类的内容时,您实际上并不是在谈论字符索引,而是指向字符索引。角色之间的空间。通过使用"foo bar".Substring(5, 1)可以明显看出第5点和第6点(5 + 1)之间的字符。这也是str.Substring(str.Length)实际上用于获取字符串末尾的空字符串的原因。

答案 2 :(得分:2)

来自the documentation

  

如果startIndex等于字符串实例的长度,则该方法返回-1。

至于为什么如果index==length像数组访问器一样,它不会抛出异常,框架设计者必须回答这个问题,因为文档没有说明,而且C#源代码最终调用内部C函数..一些未经过教育的猜测:

  • 与传统字符串函数的向后兼容性
  • Unicode支持

答案 3 :(得分:2)

MSDN清楚地说明了它可以抛出的异常。例如:

  

ArgumentOutOfRangeException

     

startIndex小于0(零)或大于此长度   字符串。

接着说:

  

索引编号从0开始.startIndex参数的范围是   0到字符串实例的长度。如果startIndex等于   字符串实例的长度,方法返回-1。

因此,关于例外情况确实没有猜测。