Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/solr/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# C中子字符串的意外行为#_C#_.net_String_Substring_Clr - Fatal编程技术网

C# C中子字符串的意外行为#

C# C中子字符串的意外行为#,c#,.net,string,substring,clr,C#,.net,String,Substring,Clr,.netSystem.String类中Substring()方法的定义如下 public string Substring(int startIndex) 其中,startIndex是根据方法定义的“此实例中子字符串的从零开始的字符位置”。如果我理解正确,这意味着它将给我字符串的一部分,从给定的从零开始的索引开始 现在,如果我有一个字符串“ABC”,并使用不同的索引获取子字符串,我会得到以下结果 var str = "ABC"; var chars = str.ToArray(); //ret

.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
为什么它不为案例[2]抛出异常

字符串有3个字符,因此索引是
[0,1,2]
,甚至
ToArray()
tocharray()
方法按预期返回3个字符!如果我尝试使用起始索引
3
Substring()
,它不应该抛出异常吗?

C中的所有字符串最后都有
字符串。空的

关于这个问题

来自MSDN-类别(系统):

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

这是一种非常明确的正确行为:

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

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

换句话说,从最后一个字符开始的子字符串将得到一个空字符串


您希望它提供字符串的一部分的注释与此不兼容。“字符串的一部分”也包括长度为零的所有子字符串集,这一点可以从以下事实得到证明:
s.substring(n,0)
也将给出一个空字符串。

基于MSDN上写的内容:

*

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

例外情况 ArgumentOutOfRangeException-startIndex小于零或大于此实例的长度

*

查看文档,如果开始索引等于长度,将返回一个空字符串

一个字符串,其长度等于 在此实例中,从startIndex开始,如果startIndex相等,则为空 到该实例的长度,且长度为零


子字符串的作用是检查startIndex是否大于字符串的长度,然后抛出异常。在您的情况下,它是相等的(字符串长度为3)。然后检查子字符串的长度是否为零,以及是否为,并返回String.Empty。在您的例子中,子字符串的长度是字符串(3)的长度减去startIndex(3)。这就是为什么子字符串的长度为0并且返回空字符串的原因。

:

首先,这被称为:

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);
}
公共字符串子字符串(int startIndex,int length)
{
如果(起始索引<0)
{
扔新的。。。
}
如果(startIndex>this.Length)
{
扔新的。。。
}
如果(长度<0)
{
扔新的。。。
}
if(startIndex>(this.Length-Length))
{
扔新的。。。
}

如果(length==0)/这里有很多技术上的答案说明框架是如何处理方法调用的,但是我想通过类比来说明为什么它是这样的

字符串
视为围栏,其中围栏面板本身是字符,由编号如下的围栏柱支撑:

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
。请注意,字符串的最后一个字符后面有一个fencepost。使用此fencepost调用函数会返回一个值,说明在该点之后没有fencepanel(即,它返回空的
字符串


类似地,
string.Substring(n,l)
返回以fencepost
n
开头的
l
面板的
字符串。这就是为什么类似于
“ABC”的东西。Substring(2,0)
也返回

为了补充其他答案,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;
}
公共字符串子字符串(int startIndex)
{
如果(startIndex==0)
归还这个;
if(startIndex<0 | | startIndex>this.length)
抛出新ArgumentOutOfRangeException(“startIndex”);
返回未选中的子字符串(startIndex,this.length-startIndex);
}
//此方法由StringBuilder.ToString()使用,并应
//始终创建新字符串对象(或返回string.Empty)。
未选中内部不安全字符串子字符串(int startIndex,int length)
{
如果(长度==0)
返回字符串。空;
字符串tmp=internalallocatest(长度);
固定(char*dest=tmp,src=this){
字符拷贝(dest、src+startIndex、长度);
}
返回tmp;
}

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

可能是一个
\0
字符(用于标记字符串的结尾)。但我不确定.NET是否使用了该字符。值得一提的是google thoughline 1246@Thank@AlexK.和其他(答案)用于指出实现和MSDN文档。我可以看到框架团队就是这样实现的,但对我(我猜也只有少数人)来说,这有点出乎意料!快速而肮脏的答案是:.NET知道0长度字符串的含义,它是d