c#中子字符串的意外行为
本文关键字:意外 字符串 | 更新日期: 2023-09-27 18:15:45
.net System.String
类中Substring()
方法的定义如下
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
为什么不对case[2]抛出异常??
字符串有3个字符,所以索引是[0, 1, 2]
,甚至ToArray()
, ToCharArray()
方法返回3个字符!
3
开始索引Substring()
,它不应该抛出异常吗?文档非常明确地说明了这是正确的行为:
返回值:与本实例中以startIndex开头的子字符串相等的字符串,或者如果startIndex等于本实例的长度则为空
如果startIndex
小于0或*大于此实例的长度,抛出
ArgumentOutOfRangeException
。*
换句话说,从最后一个字符后面开始的子字符串将得到一个空字符串。
您希望它给您字符串的部分的注释与此不兼容。"字符串的一部分"也包括所有长度为零的子字符串的集合,s.substring(n, 0)
将也给出一个空字符串。
这里有很多关于框架如何处理方法调用的技术答案,但我想通过类比对给出一个推理,为什么是这样的。
将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 n
开头的面板的string
。注意,字符串的最后一个字符后面有一个栅栏柱。用这个栅栏柱调用函数将返回一个值,表示在此点之后没有栅栏板(即。它返回空的string
)。
同样,string.Substring(n, l)
返回以fencepost n
开头的l
面板的string
。这就是为什么像"ABC".Substring(2, 0)
这样的东西也返回""
。
有时查看代码会很方便:
首先是
public string Substring(int startIndex)
{
return this.Substring(startIndex, this.Length - startIndex);
}
由于value的减法,长度为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);
}
根据MSDN上的内容:
*返回值 -与本实例中以startIndex开头的子字符串相等的字符串,如果startIndex等于本实例的长度则为空。
ArgumentOutOfRangeException - startIndex小于零或大于此实例的长度
*查看字符串。Substring方法文档,如果起始索引等于长度,则返回空字符串。
与长度为length的子字符串长度相等的字符串在此实例中,从startIndex开始,如果startIndex相等,则为空到此实例的长度,且length为0。
Substring的作用是检查startIndex是否大于字符串的长度,然后才抛出异常。在你的例子中,它是相等的(字符串长度为3)。之后,它检查子字符串的长度是否为零,如果是则返回string . empty。在您的例子中,子字符串的长度是字符串(3)减去startIndex(3)的长度。这就是子字符串的长度为0并返回空字符串的原因。
c#中所有的字符串最终都有String.Empty
.
这个问题有一个很好的答案。
From MSDN - String
Class (System):
在。net框架中,String对象可以包含嵌入的null字符,作为字符串长度的一部分。然而,在在某些语言(如C和c++)中,null字符表示结束弦的;它不被认为是字符串的一部分,也不是作为字符串长度的一部分。
为了补充其他答案,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。如果长度等于0,则为空。