3

SSCLI声明中一些 C++ 代码中的注释,指的是 String.Chars 属性的非托管内部实现:

这种方法实际上并没有使用。JIT 将为字符串类上的索引器方法生成代码。

那么......这是什么神奇的代码?我理解抖动的全部意义在于它们在不同的情况下会产生不同的代码。但至少,对于现代 x64 Windows 7+ 平台,/a 抖动如何实现这一点?或者那是真正的秘密酱汁?

额外细节

不久前,我正在寻找在 C# 中迭代​​字符串中单个字符的最快方法。结果证明,不使用不安全代码或复制内容(通过ToCharArray())的最快方法是内置字符串索引器,它实际上是对String.Chars 属性的调用。就在我最初的问题中,我问是否有人对索引器的实际工作有深入的了解,但是尽管 Skeet 和 Lippert 都遇到了问题,但我没有得到任何回应。所以我决定自己深入研究:

停止 1:mscorlib

通过使用 ildasm 检查 mscorlib.dll,我们可以看到它String::get_Chars(int32 index)只是一个internalcall指针(加上一个属性):

.method public hidebysig specialname instance char 
        get_Chars(int32 index) cil managed internalcall
{
  .custom instance void System.Security.SecuritySafeCriticalAttribute::.ctor() = ( 01 00 00 00 ) 
} // end of method String::get_Chars

正如MethodImplOptions 枚举的文档中所述,“内部调用是对在公共语言运行时本身内实现的方法的调用。” 2004 年 MSDN 杂志的文章和SO 帖子都表明internalcall名称到非托管实现的映射可以在共享源 CLI内的 ecall.cpp 中找到。

第 2 站:ecapp.cpp

搜索ecall.cpp 的在线副本显示它get_Chars是由以下人员实现的COMString::GetCharAt

FCIntrinsic("get_Chars", COMString::GetCharAt, CORINFO_INTRINSIC_StringGetChar)

第 3 站:comstring.cpp

comstring.cpp确实包含 GetCharAt 的实现,从第 1219 行开始。除了,它前面有以下注释:

/*==================================GETCHARAT===================================
**Returns the character at position index.  Thows IndexOutOfRangeException as
**appropriate.
**This method is not actually used. JIT will generate code for indexer method on string class.
**
==============================================================================*/
4

1 回答 1

1

首先,请参阅 Hans Passant 对关键部分的评论。

String在早期的 .NET(CLR 1 和 2)中,CLR 对和StringBuilder类型有相当多的特殊支持。事实上,这两种类型非常紧密地结合在一起,StringBuilder.ToString不会将实际字符复制到任何地方,字符串索引器仍然使用特殊的抖动支持从同一内存位置获取字符。我认为抖动支持String.Chars最初是为了避免通过堆栈传递索引整数,但从那时起抖动似乎有所改善。

.NET 4 附带了一个不同的StringBuilder (ropes ) 实现,不再依赖于如何String处理。(它必须在 期间复制ToString,但追加速度要快得多。)在这些更改之后,

  • StringBuilder索引器在大字符串上 显着减慢到O(log n) 。见这里。它从不内联,即使在短字符串上也不行。
  • Stringindexer 仍然使用(未发布的)特殊抖动支持。我希望这个基本上可以内联到移位、加法和内存提取,或者最近的循环允许的更快的东西。
于 2012-07-17T08:58:37.080 回答