5. 文字列のインスタンス
C# の文字列は不変です
§8.2.1 Predefined types
The predefined reference types are object and string. The type object is the ultimate
base type of all other types. The type string is used to represent Unicode string values.
Values of type string are immutable.
[訳]
神は object と string という参照型を作りたもうた。 object は万物の根源である。 string
は Unicode 文字列をあらわす。何人も string の値を
変えることはできない。
– ECMA-334 C# Language Specification, p. 17.
“
6. Insert とか Remove とかあるじゃん
… ご存知のとおり、新しい文字列になって返ってきます
string String.Insert(int, string)
“Returns a new string in which a specified string is inserted at a specified index position in this instance.”
– https://msdn.microsoft.com/library/system.string.insert.aspx
string String.Remove(int, int)
“Returns a new string in which a specified number of characters in the current instance beginning at a
specified position have been deleted.”
– https://msdn.microsoft.com/library/system.string.remove.aspx
8. 中身を変えたければ、どうするの?
System.Text.StringBuilder を使いましょう
StringBuilder StringBuilder.Insert(int, string)
“Inserts a string into this instance at the specified character position.”
– https://msdn.microsoft.com/library/system.text.stringbuilder.insert.aspx
StringBuilder StringBuilder.Remove(int, int)
“Removes the specified range of characters from this instance.”
– https://msdn.microsoft.com/library/system.text.stringbuilder.remove.aspx
9. 中身を変えたければ、どうするの?
public StringBuilder Remove(int startIndex, int length) {
// ...
if (length > 0)
{
StringBuilder chunk;
int indexInChunk;
Remove(startIndex, length, out chunk, out indexInChunk);
}
return this;
}
– Reference Source for .NET 4.6
– ndpclrsrcbclsystemtextstringbuilder.cs (Line. 865 – 893, excerpted)
← インスタンス自身がそのまま返る
15. ところでなぜ String を char* で fixed できるのか
仕様です。
§27.6 The fixed statement
An expression of type string, provided the type char* is implicitly convertible to the pointer
type given in the fixed statement. In this case, the initializer computes the address of the
first character in the string, and the entire string is guaranteed to remain at a fixed address
for the duration of the fixed statement.
[訳]
string 型の式は char* 型が与えられたなら fixed によりポインタに暗黙変換できる。
このとき初期化子では文字列の先頭アドレスが計算されて、 fixed スコープ中
では文字列全体が固定アドレスに留まることが保障される。
– ECMA-334 C# Language Specification, p. 437.
“
17. 文字列のインスタンス (復習)
C# の文字列は不変です
§8.2.1 Predefined types
The predefined reference types are object and string. The type object is the ultimate
base type of all other types. The type string is used to represent Unicode string values.
Values of type string are immutable.
[訳]
神は object と string という参照型を作りたもうた。 object は万物の根源である。 string
は Unicode 文字列をあらわす。何人も string の値を
変えることはできない。
– ECMA-334 C# Language Specification, p. 17.
“
18. 文字列のインスタンス
C# の文字列が、不変だと思っていたでしょう! … 違います (ガタッ)
§27.6 The fixed statement
Modifying objects of managed type through fixed pointers can result in undefined behavior.
[Note: For example, because strings are immutable, it is the programmer’s responsibility to
ensure that the characters referenced by a pointer to a fixed string are not modified. end
note]
[超意訳]
文字列はホントは不変だけど、ポインタで参照された文字列を変えてもイイよ!
責任取れるならね! (^ρ^)
– ECMA-334 C# Language Specification, p. 439.
“
21. 文字列クラスの双対性 (デュアリティ)
public sealed class String : IComparable, ICloneable, IConvertible, IEnumerable
{
[NonSerialized]private int m_stringLength;
[NonSerialized]private char m_firstChar;
– Reference Source for .NET 4.6
– ndpclrsrcbclsystemstring.cs (Line. 48 – 60, excerpted)
対応付け
class StringObject : public Object
{
DWORD m_StringLength;
WCHAR m_Characters[0];
– .NET CoreCLR (https://github.com/dotnet/coreclr)
– src/vm/object.h (Line. 1087 – 1099, excerpted)
22. 文字列インスタンスの生成は特殊
LEAF_ENTRY AllocateStringFastMP_InlineGetThread, _TEXT
; We were passed the number of characters in ECX
; we need to load the method table for string from the global
mov r9, [g_pStringClass]
; Instead of doing elaborate overflow checks, we just limit the number of elements
; to (LARGE_OBJECT_SIZE - 256)/sizeof(WCHAR) or less.
; This will avoid all overflow problems, as well as making sure
; big string objects are correctly allocated in the big object heap.
cmp ecx, (ASM_LARGE_OBJECT_SIZE - 256)/2
jae OversizedString
mov edx, [r9 + OFFSET__MethodTable__m_BaseSize]
; Calculate the final size to allocate.
; We need to calculate baseSize + cnt*2, then round that up by adding 7 and anding ~7.
lea edx, [edx + ecx*2 + 7]
and edx, -8
(… 続く)
← String 型の情報を読み込み
← 文字列長の評価。大きすぎるときは別方法で割り当て
← 型のベース サイズを評価(C++ の WCHAR[0] はこのため)
← 最終的に必要な領域の計算