2017-05-24 72 views
4

Microsoft.Extensions.Primitives包LIB还有一类StringSegment的量,评论表明,它是:StringSegment类的用途是什么?

子串的优化的表示。

我不知道这个特定类的,直到我发现aspnet announcement #244,他说:Microsoft.Net.Http.Headers转换为使用StringSegments

不过,看着implementation of the StringSegment这个班,我没有看到它实际服务的目的。我看到一个缓冲区,我猜想这个缓冲区可能会更好地处理部分字符('segment'部分也许?)。我还会看到几个辅助函数,它们的行为与已有的常规字符串(如StartsWith/Endswith,Substring等)的行为密切相关 - 如果不完全相同 - aspnet-core docs将完整列出这些函数,但同样缺乏“为什么“应该使用它。

那么StringSegment类的目的究竟是什么,以及在哪些场景适用于它?

当我操纵字符串时,在我的应用程序代码中调用类是否有用? 我们可以举个例子吗?

+0

那么,http头是一个很好的例子。他们必须被解析,但客户端代码很少对他们感兴趣。所以懒洋洋地生成它们可以避免一堆GC垃圾。 –

+0

@HansPassant你不需要'StringSegment'。在这种情况下,您可以在获取请求的Headers属性时解析头文件。如果你创建了'StringSegments',那么你就不必要地为所有的字符串段创建了所有的对象。 – Servy

回答

2

它允许您对另一个字符串的子字符串执行各种字符串操作,没有实际上调用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 Bufferint Offsetint Length都是只读的。

而且Value属性:

public string Value 
    { 
     get 
     { 
      if (!HasValue) 
      { 
       return null; 
      } 
      else 
      { 
       return Buffer.Substring(Offset, Length); 
      } 
     } 
    } 

这样你就可以相对便宜地创造这些东西,如果你想在一些较大的字符串暴露的潜在大“子”的集合。如果没有人打电话Value.getSubstring永远不会被调用。如果你有很多这样的消费者,并且消费者只能获得其中一个或两个的价值,那么你就避免了大量致电Substring()的电话。

正如Servy所观察到的,如果您在同一个对象上调用两次Value,那么您会调用Buffer.Substring(Offset, Length);两次,而不是完全没有。如果你还在避开另外20个电话,那很容易成为净收益。您可能想知道为什么他们没有缓存Buffer.Substring()的返回值。我不知道这是因为实习生而不必要的,或者如果在实践中发现这种优化不值得努力。

+0

正如您之前的评论所述,不,这只是不正确。重点不在于延迟操作员,直到以后。 *目标*是*完全避免进行操作*。如果你发现自己经常使用StringSegment的'Value',你没有得到任何好处,并且你可能会导致自己*问题*。当然,这并不意味着你不应该使用这个,而应该只在你创建的一小部分实例上调用它。 – Servy

+0

@Servy很明显,如果有人获得了'Value'两次,整个事情就会适得其反 - 除非有一些优化,第二次调用'Buffer.Substring(Offset,Length);'会返回相同的实例化字符串对象。 –

+1

不,如果他们在每个子字符串*上调用一次*他们仍然没有从使用中受益。这个类的全部目的是你应该调用它*每个实例少于一次*,理想上*显着*少,否则你应该只使用普通的子字符串。 – Servy

0

解析文本时,可能会创建或复制许多新的字符串对象。理论上这个类有助于减少处理大型子字符串时使用的内存。其他语言也有类似的概念(请参阅C++ 17中的std :: string_view)