令人惊讶的子串行为

时间:2012-07-28 21:57:57

标签: c# string

我在使用Substring方法时遇到了这种行为:

static void Main(string[] args) {
    string test = "123";
    for (int i = 0; true; i++) {
        try {
            Console.WriteLine("\"{0}\".Substring({1}) is \"{2}\"", test, i, test.Substring(i));
        } catch (ArgumentOutOfRangeException e) {
            Console.WriteLine("\"{0}\".Substring({1}) threw an exception.", test, i);
                break;
        }
    }
}

输出:

"123".Substring(0) is "123"
"123".Substring(1) is "23"
"123".Substring(2) is "3"
"123".Substring(3) is ""
"123".Substring(4) threw an exception.

“123”.Substring(3)返回一个空字符串和“123”.Substring(4)抛出异常。然而,“123”[3]和“123”[4]都是出界的。这是documented on MSDN,但我很难理解为什么以这种方式编写Substring方法。我希望任何越界索引要么总是导致异常,要么总是导致空字符串。有什么见解吗?

4 个答案:

答案 0 :(得分:13)

String.Substring(startindex)的内部实施就像这样

public string Substring(int startIndex)
{
    return this.Substring(startIndex, this.Length - startIndex);
}

所以你要求一个零字符长度的字符串。 (A.K.A. String.Empty) 我同意你的观点,这在MS部分尚不清楚,但如果没有更好的解释,我认为给出这个结果比抛出异常更好。

深入了解String.Substring(startIndex, length)的实施,我们看到了这段代码

if (length == 0)
{
    return Empty;
}

因此,因为length = 0是第二次重载中的有效输入,所以我们也得到第一次的结果。

答案 1 :(得分:2)

.Net-Substring的文档明确指出,如果索引大于字符串的长度,则抛出异常,在“123”为3的情况下。

我想原因可能是因为兼容性,要创建与C ++子串函数相同的行为。在C ++中,

test.substr(3)
由于NULL终止,

将返回一个空字符串,这意味着字符串“123”实际上包含4个字符! (最后一个是\ 0)。

这可能是出现这种行为的意图,即使每个规范的.Net都没有以空字符结尾的字符串(尽管实现实际上......)

答案 2 :(得分:1)

这个实现提供的一个便利是,如果你有一个循环对一些任意字符串做某事(例如,返回字符串的后半部分),你就不必将空字符串作为特殊处理情况下。

答案 3 :(得分:1)

不知道为什么,不能想出一个很好的理由,但我想如果你想检查一个子串调用是否在一个字符串的末尾,返回string.Empty比抛出异常便宜。< / p>

另外我想你只是要求索引字符后面的字符串部分为空白,而之后的索引真的超出范围