有谁知道如何使用这种方法?文档有点"轻"!
public static string Create<TState> (int length, TState state, System.Buffers.SpanAction<char,TState> action);
Run Code Online (Sandbox Code Playgroud)
https://docs.microsoft.com/en-us/dotnet/api/system.string.create?view=netcore-2.2
Joe*_*orn 31
该String.Create()方法需要三件事:
length字符串的最后一个.您必须事先知道这一点,因为该方法需要安全地创建Span<char>用于构造最终字符串的内部实例.state)将成为你的字符串.例如,您可能有一个数组缓冲区(例如,通过网络接收的ascii整数),但它可能是任何东西.这是将转换为字符串的原始数据.这篇MSDN文章中深深埋藏了一个例子,甚至使用了一个Random实例.我还看到一个不完整的例子,用于创建位图图像(可变大小的state输入)的base-64编码哈希值(固定长度),但遗憾的是我再也找不到它.action拉姆达功能转化state成最终的字符串中的字符.该Create()方法将调用此函数,Span<char>将为字符串创建的内部函数和您的state数据作为参数传递.对于一个非常简单的示例,我们可以Create()使用如下字符数组的字符串:
char[] buffer = {'f', 'o', 'o'};
string result = string.Create(buffer.Length, buffer, (chars, buf) => {
for (int i=0;i<chars.Length;i++) chars[i] = buf[i];
});
Run Code Online (Sandbox Code Playgroud)
当然,基本string(char[])也可以在这里工作,但这显示了正确的功能可能是什么样子.或者我们可以将ascii int值数组映射到一个新的字符串,如下所示:
int[] buffer = {102, 111, 111};
string result = string.Create(buffer.Length, buffer, (chars, buf) => {
for (int i=0;i<chars.Length;i++) chars[i] = (char)buf[i];
});
Run Code Online (Sandbox Code Playgroud)
该函数的存在是因为与传统方法相比,该技术有一些显着的潜在性能优势.例如,您可以直接将Stream对象传递给String.Create()(假设您知道最终长度),而不是将Stream读入缓冲区.这避免了需要分配缓冲区并避免一轮复制值(stream => buffer => string变为stream => string).
调用时会发生什么,string.Create()该函数构造一个已经具有由您的length参数确定的大小的新字符串.这是一个(也是唯一一个)堆分配.因为它Create()是字符串类型的成员,所以它可以访问您和我通常看不到的这个新对象的私有字符串数据.它现在使用此访问权来创建Span<char>指向新字符串的内部缓冲区的内部实例.
它Span<char>存在于堆栈中,但是从新字符串作用于堆内存...没有额外的分配,并且一旦Create()函数返回它就完全超出范围,所以一切都是合法且安全的.而且因为它基本上是一个带指针的好处,除非你做了其他可怕的错误,否则几乎没有溢出堆栈的风险.
现在Create()调用你的action函数来完成填充字符串的繁重工作.你的actionlambda可以写入Span<char>...在你的lamdba执行期间,字符串比你听到的更不可变!
当actionlamdba被finshed时,Create()可以返回新的,准备使用的字符串引用.一切都很好:我们最小化堆分配,保持类型安全和内存安全; 将Span<char>不再是您随时随地访问,并作为一个堆栈值已经被破坏.我们还根据您的action实现最小化了缓冲区之间不必要的复制.
| 归档时间: |
|
| 查看次数: |
1391 次 |
| 最近记录: |