它允许您对另一个字符串的子字符串执行各种字符串操作,没有实际上调用Substring()
并创建一个新的字符串对象。这大致类似于在C这样你可以有一个指针到一个字符串中间:
char * s1 = "foo bar";
char * s2 = p + 4;
s2
“是”字符串“bar”,在一个有用的意义。
就拿StringSegment.IndexOf()
:你可以在弦线段一个字符的索引,而不必首先调用Substring()
在较大的字符串并分配一个新的缓冲区:
public int IndexOf(char c, int start)
{
return IndexOf(c, start, Length - start);
}
可以“微调”在StringSegment
为“删除”的空白,以及:
public StringSegment TrimStart()
{
var trimmedStart = Offset;
while (trimmedStart < Offset + Length)
{
if (!char.IsWhiteSpace(Buffer, trimmedStart))
{
break;
}
trimmedStart++;
}
return new StringSegment(Buffer, trimmedStart, Offset + Length - trimmedStart);
}
这些都是非常便宜的操作,没有分配等。
你可以通过自己玩索引来完成所有这些工作,但是那种代码很烦人,而且容易出错。你更愿意围绕它抽象抽象。
这也是一个“延期”致电String.Substring()
。 (希望)得到的是,如果你创建了一些这样的类,那么绝大多数或全部都不会返回实际的子字符串。
看构造函数:
public StringSegment(string buffer, int offset, int length)
公共属性String Buffer
,int Offset
和int Length
都是只读的。
而且Value
属性:
public string Value
{
get
{
if (!HasValue)
{
return null;
}
else
{
return Buffer.Substring(Offset, Length);
}
}
}
这样你就可以相对便宜地创造这些东西,如果你想在一些较大的字符串暴露的潜在大“子”的集合。如果没有人打电话Value.get
,Substring
永远不会被调用。如果你有很多这样的消费者,并且消费者只能获得其中一个或两个的价值,那么你就避免了大量致电Substring()
的电话。
正如Servy所观察到的,如果您在同一个对象上调用两次Value
,那么您会调用Buffer.Substring(Offset, Length);
两次,而不是完全没有。如果你还在避开另外20个电话,那很容易成为净收益。您可能想知道为什么他们没有缓存Buffer.Substring()
的返回值。我不知道这是因为实习生而不必要的,或者如果在实践中发现这种优化不值得努力。
那么,http头是一个很好的例子。他们必须被解析,但客户端代码很少对他们感兴趣。所以懒洋洋地生成它们可以避免一堆GC垃圾。 –
@HansPassant你不需要'StringSegment'。在这种情况下,您可以在获取请求的Headers属性时解析头文件。如果你创建了'StringSegments',那么你就不必要地为所有的字符串段创建了所有的对象。 – Servy