C#

时间:2015-10-02 11:35:51

标签: c# .net string substring clr

.net Substring()类中System.String方法的定义就像这样

public string Substring(int startIndex)

其中startIndex“根据方法定义,此实例中子字符串从零开始的字符位置”。如果我理解正确,这意味着它将给我一部分字符串,从给定的从零开始的索引开始。

现在,如果我有一个字符串"ABC"并使用不同索引的子字符串,我会得到以下结果。

var str = "ABC";
var chars = str.ToArray(); //returns 3 char 'A', 'B', 'C' as expected

var sub2 = str.Substring(2); //[1] returns "C" as expected
var sub3 = str.Substring(3); //[2] returns "" ...!!! Why no exception??
var sub4 = str.Substring(4); //[3] throws ArgumentOutOfRangeException as expected

为什么它不会为案例[2]抛出异常?

该字符串有3个字符,因此索引为[0, 1, 2],甚至ToArray()ToCharArray()方法按预期返回3个字符!如果我尝试Substring()使用起始索引3

,它是否应该抛出异常

8 个答案:

答案 0 :(得分:51)

documentation非常清楚这是正确的行为:

  

返回值:一个字符串,相当于在此实例中以startIndex开头的子字符串,或 如果startIndex等于此实例的长度,则为空。 < / p>      

如果ArgumentOutOfRangeException小于零或 *大于此实例的长度,则抛出startIndex。 *

换句话说,从最后一个字符开始的子字符串将为您提供一个空字符串。

您希望它为您提供字符串的部分的评论与此不相容。 “字符串的一部分”也包括零长度的所有子串的集合,s.substring(n, 0)给出一个空字符串这一事实证明了这一点。

答案 1 :(得分:23)

这里有很多技术答案说明框架如何处理方法调用,但是我想通过类比为为什么给出一个推理。

string视为栅栏,其中栅栏面板本身就是字符,用栅栏柱固定,编号如下所示:

0   1   2   3
| A | B | C |   "ABC"

0   1   2   3   4   5   6   7   8   9
| M | y |   | S | t | r | i | n | g |   "My String"

在此类比中,string.Substring(n)返回以fencepost string开头的n个面板。请注意,字符串的最后一个字符后面有一个围栅栏。使用此fence post调用该函数会返回一个值,表明此点后没有fence面板(即返回空string)。

同样,string.Substring(n, l)会以fencepost string开头,返回ln个面板。这就是"ABC".Substring(2, 0)之类的内容也会返回""的原因。

答案 2 :(得分:12)

Sometimes looking at the code can be handy

首先这叫做:

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

由于减去值,长度为0:

public string Substring(int startIndex, int length)
{
    if (startIndex < 0)
    {
        throw new ...
    }
    if (startIndex > this.Length)
    {
        throw new ...
    }
    if (length < 0)
    {
        throw new ...
    }
    if (startIndex > (this.Length - length))
    {
         throw new ...
    }
    if (length == 0) // <-- NOTICE HERE
    {
        return Empty;
    }
    if ((startIndex == 0) && (length == this.Length))
    {
        return this;
    }
    return this.InternalSubString(startIndex, length);
}

答案 3 :(得分:4)

根据MSDN上的内容:

*

返回值 - 一个字符串,相当于在此实例中以startIndex开头的子字符串,如果startIndex等于此实例的长度,则为Empty。

<强>例外 ArgumentOutOfRangeException - startIndex小于零或大于此实例的长度

*

答案 4 :(得分:4)

查看String.Substring Method文档,如果起始索引等于长度,将返回一个空字符串。

  

一个字符串,它等于长度为length的子字符串   在此实例中从startIndex开始,如果startIndex相等则为Empty   到这个实例的长度,长度为零。

答案 5 :(得分:2)

Substring的作用是检查startIndex是否大于字符串的长度,然后它才会抛出异常。在你的情况下,它是相等的(字符串长度是3)。之后,它检查子串的长度是否为零,如果返回String.Empty。在您的情况下,子字符串的长度是字符串(3)的长度减去startIndex(3)。这就是子串的长度为0并返回空字符串的原因。

答案 6 :(得分:1)

C#中的所有字符串最后都有String.Empty

Here is good answer关于这个问题。

来自MSDN - String班级(系统):

  

在.NET Framework中,String对象可以包含嵌入的null   字符,计算为字符串长度的一部分。但是,在   某些语言,如C和C ++,空字符表示结束   一串;它不被认为是字符串的一部分而不是   算作字符串长度的一部分。

答案 7 :(得分:1)

为了补充其他答案,Mono也正确地实现了这种行为。

public String Substring (int startIndex)
{
    if (startIndex == 0)
        return this;
    if (startIndex < 0 || startIndex > this.length)
        throw new ArgumentOutOfRangeException ("startIndex");

    return SubstringUnchecked (startIndex, this.length - startIndex);
}

// This method is used by StringBuilder.ToString() and is expected to
// always create a new string object (or return String.Empty). 
internal unsafe String SubstringUnchecked (int startIndex, int length)
{
    if (length == 0)
        return String.Empty;

    string tmp = InternalAllocateStr (length);
    fixed (char* dest = tmp, src = this) {
        CharCopy (dest, src + startIndex, length);
    }
    return tmp;
}

如您所见,如果长度等于零,则返回String.Empty。