C#の可変文字列と不変文字列の違いは何ですか?
C#の可変文字列と不変文字列の違いは何ですか?
回答:
ミュータブルとイミュータブルは、それぞれ「変更可能」と「変更不可」を意味する英語の単語です。単語の意味はITのコンテキストでも同じです。すなわち
これらの単語の意味は、C#/ .NETでも他のプログラミング言語/環境と同じですが、(明らかに)タイプの名前が他の詳細と異なる場合があります。
記録のために:
String
標準のC#/ .Net不変文字列型です StringBuilder
標準のC#/ .Net可変文字列型 C#として表される文字列に「変更を加える」には、String
実際に新しいString
オブジェクトを作成します。オリジナルString
は変更できないので変更されません...
ほとんどの場合String
、それらについてのより簡単な理由なので、使用する方が良いです。例えば、他のスレッドが「私の文字列を変更する」可能性を考慮する必要はありません。ただし、一連の操作を使用して文字列を作成または変更する必要がある場合は、を使用する方が効率的StringBuilder
です。
そして最後に、a StringBuilder
は不変ではないため文字列ではないと断言する人々のために、MicrosoftのドキュメントはStringBuilder
こう記述しています:
「変更可能な文字列を表します。このクラスは継承できません。」
String
不変です
つまり、文字列は変更できません。文字列を変更する(たとえば、文字列に追加する)と、実際には新しい文字列が作成されます。
だが StringBuilder
、不変ではありません(むしろ、変更可能です)
したがって、複数の連結など、文字列を何度も変更する必要がある場合は、を使用しますStringBuilder
。
O(N^2)
行動につながる...
オブジェクトは、一度作成されると、そのオブジェクトに対するさまざまな操作を呼び出すことによって状態を変更できる場合は変更可能です。それ以外の場合は変更できません。
C#(および.NET)では、文字列はSystem.Stringクラスで表されます。string
キーワードは、このクラスのエイリアスです。
System.Stringクラスは、すなわち一度その状態を変更することはできません作成され不変です。
だからあなたのような文字列に対して実行するすべての操作はSubstring
、Remove
、Replace
、などの「+」演算子を使用して連結は、新しい文字列を作成し、それを返します。
デモについては、次のプログラムを参照してください-
string str = "mystring";
string newString = str.Substring(2);
Console.WriteLine(newString);
Console.WriteLine(str);
これにより、それぞれ「string」と「mystring」が出力されます。
不変性の利点と文字列が不変である理由の確認.NET文字列が不変である理由 。
頻繁に変更する文字列が必要な場合は、StringBuilder
クラスを使用できます。インスタンスに対する操作は StringBuilder
、同じオブジェクトを変更します。
詳細なアドバイスのために使用する際 StringBuilder
に参照するのStringBuilderを使用する場合は?。
すべてのstring
オブジェクトはC#では不変です。クラスのオブジェクトはstring
、いったん作成されると、作成時に使用したもの以外の値を表すことはできません。文字列を「変更」するように見えるすべての操作は、代わりに新しい文字列を生成します。これはメモリに関しては非効率的ですが、参照が変更されない限り、参照されている文字列は変更されないため、文字列があなたのもとで形式が変更されないことを信頼できるという点で非常に役立ちます。
対照的に、可変オブジェクトには変更可能なデータフィールドがあります。そのメソッドの1つまたは複数がオブジェクトの内容を変更するか、書き込み時にオブジェクトの値を変更するプロパティを持っています。
変更可能なオブジェクト(Stringに最も類似したオブジェクト)がある場合は、そのオブジェクトがStringBuffer
自分から変更されないことを確実にしたい場合は、そのオブジェクトのコピーを作成する必要があります。これが、可変オブジェクトがあらゆる形式のキーとして使用するのが危険な理由ですDictionary
またはセットのです。オブジェクト自体が変更される可能性があり、データ構造が知る方法がなく、データが破損し、最終的にはプログラムがクラッシュします。
ただし、その内容を変更することはできます。つまり、単一の文字などを変更したいため、完全なコピーを作成するよりもはるかにメモリ効率が高くなります。
一般に、正しいことは、何かを作成している間は可変オブジェクトを使用し、完了したら不変オブジェクトを使用することです。もちろん、これは不変のフォームを持つオブジェクトに適用されます。ほとんどのコレクションにはありません。ただし、コレクションの内部状態を他のコンテキストに送信するときに、コレクションの読み取り専用の形式を提供することはしばしば有用です。データ。
不変:
オブジェクトに対して何らかの操作を行うと、新しいオブジェクトが作成されるため、文字列の場合のように状態を変更することはできません。
可変
オブジェクトに対して何らかの操作を実行すると、StringBuilderの場合のように、オブジェクト自体が新しいオブジェクトを変更することなく作成されます
.NETでは、System.String(別名文字列)は不変オブジェクトです。つまり、オブジェクトを作成するときに、その値を後で変更することはできません。不変オブジェクトのみを再作成できます。
System.Text.StringBuilderはSystem.Stringと同等の変更可能であり、その値を変更できます
例えば:
class Program
{
static void Main(string[] args)
{
System.String str = "inital value";
str = "\nsecond value";
str = "\nthird value";
StringBuilder sb = new StringBuilder();
sb.Append("initial value");
sb.AppendLine("second value");
sb.AppendLine("third value");
}
}
次のMSILを生成します。コードを調査する場合。System.Stringのオブジェクトを変更するたびに、実際に新しいオブジェクトを作成していることがわかります。ただし、System.Text.StringBuilderでは、テキストの値を変更するたびにオブジェクトを再作成しません。
.method private hidebysig static void Main(string[] args) cil managed
{
.entrypoint
// Code size 62 (0x3e)
.maxstack 2
.locals init ([0] string str,
[1] class [mscorlib]System.Text.StringBuilder sb)
IL_0000: nop
IL_0001: ldstr "inital value"
IL_0006: stloc.0
IL_0007: ldstr "\nsecond value"
IL_000c: stloc.0
IL_000d: ldstr "\nthird value"
IL_0012: stloc.0
IL_0013: newobj instance void [mscorlib]System.Text.StringBuilder::.ctor()
IL_0018: stloc.1
IL_0019: ldloc.1
IL_001a: ldstr "initial value"
IL_001f: callvirt instance class [mscorlib]System.Text.StringBuilder [mscorlib]System.Text.StringBuilder::Append(string)
IL_0024: pop
IL_0025: ldloc.1
IL_0026: ldstr "second value"
IL_002b: callvirt instance class [mscorlib]System.Text.StringBuilder [mscorlib]System.Text.StringBuilder::AppendLine(string)
IL_0030: pop
IL_0031: ldloc.1
IL_0032: ldstr "third value"
IL_0037: callvirt instance class [mscorlib]System.Text.StringBuilder [mscorlib]System.Text.StringBuilder::AppendLine(string)
IL_003c: pop
IL_003d: ret
} // end of method Program::Main
.NETは舞台裏で文字列プールを使用するため、文字列は変更可能です。その意味は :
string name = "My Country";
string name2 = "My Country";
nameとname2の両方が、文字列プールの同じメモリロケーションを参照しています。次に、name2を次のように変更するとします。
name2 = "My Loving Country";
文字列「My Loving Country」の文字列プールを調べ、見つかった場合はその文字列の参照を取得します。別の賢明な新しい文字列「My Loving Country」が文字列プールに作成され、name2が文字列の参照を取得します。しかし、名前のような他の変数がまだそれを使用しているため、このプロセス全体「私の国」は変更されませんでした。そして、それがstringがIMMUTABLEである理由です。
StringBuilderはさまざまな方法で機能し、文字列プールを使用しません。StringBuilderのインスタンスを作成するとき:
var address = new StringBuilder(500);
このインスタンスにサイズ500バイトのメモリチャンクを割り当て、すべての操作でこのメモリの場所を変更するだけで、このメモリは他のオブジェクトと共有されません。そして、それがStringBuilderがMUTABLEである理由です。
お役に立てば幸いです。
実際にはありません。Stringクラスは変更可能です。
unsafe
{
string foo = string.Copy("I am immutable.");
fixed (char* pChar = foo)
{
char* pFoo = pChar;
pFoo[5] = ' ';
pFoo[6] = ' ';
}
Console.WriteLine(foo); // "I am mutable."
}
この種のロジックは、実際にはStringクラスとStringBuilderクラスで常に実行されます。Concat、Substringなどを呼び出すたびに新しい文字列を割り当て、ポインター演算を使用して新しい文字列にコピーするだけです。文字列はそれ自体が変化しないため、「不変」と見なされるのはなぜですか。
ところで、ないではない文字列リテラルでこれをしようとしたり、あなたのプログラムまで混乱ひどくなります:
string bar = "I am a string.";
fixed (char* pChar = bar)
{
char* pBar = pChar;
pBar[2] = ' ';
}
string baz = "I am a string.";
Console.WriteLine(baz); // "I m a string."
これは、文字列リテラルがデスクトップ.NET Frameworkにインターンされるためです。つまり、まったく同じ文字列bar
をbaz
指すので、一方を変更するともう一方も変更されます。WinRTのような管理されていないプラットフォームを使用している場合、文字列のインターニングが欠けているので、これはすべて問題ありません。
明確にするために、C#(または一般に.NET)には変更可能な文字列などはありません。他の言語は変更可能な文字列(変更可能な文字列)をサポートしていますが、.NETフレームワークはサポートしていません。
したがって、あなたの質問に対する正しい答えは、C#ではすべての文字列が不変であることです。
文字列には特定の意味があります。"string"の小文字のキーワードは、System.Stringクラスからインスタンス化されたオブジェクトのショートカットにすぎません。文字列クラスから作成されたすべてのオブジェクトは常に不変です。
テキストの変更可能な表現が必要な場合は、StringBuilderなどの別のクラスを使用する必要があります。StringBuilderを使用すると、「単語」のコレクションを繰り返し作成してから、それを文字列に変換できます(もう一度不変です)。
StringBuilder
はこれと矛盾します。msdn.microsoft.com
http://yassershaikh.com/what-is-the-difference-between-strings-and-stringbuilder-in-c-net/から
短い答え:StringBuilderは変更可能ですが、Stringは不変です。
どういう意味ですか ?Wikiによると、オブジェクト指向では、不変オブジェクトとは、作成後に状態を変更できないオブジェクトのことです。これは、作成後に変更できる可変オブジェクトとは対照的です。
StringBuilderクラスのドキュメントから:
Stringオブジェクトは不変です。System.Stringクラスのメソッドの1つを使用するたびに、メモリ内に新しい文字列オブジェクトを作成します。これには、その新しいオブジェクトに新しい領域を割り当てる必要があります。
文字列に繰り返し変更を加える必要がある状況では、新しいStringオブジェクトの作成に関連するオーバーヘッドが高くつく可能性があります。
System.Text.StringBuilderクラスは、新しいオブジェクトを作成せずに文字列を変更する場合に使用できます。たとえば、StringBuilderクラスを使用すると、ループ内で多数の文字列を連結するときにパフォーマンスを向上させることができます。
これは、不変文字列と可変文字列ビルダーの例です
Console.WriteLine("Mutable String Builder");
Console.WriteLine("....................................");
Console.WriteLine();
StringBuilder sb = new StringBuilder("Very Good Morning");
Console.WriteLine(sb.ToString());
sb.Remove(0, 5);
Console.WriteLine(sb.ToString());
Console.WriteLine();
Console.WriteLine("Immutable String");
Console.WriteLine("....................................");
Console.WriteLine();
string s = "Very Good Morning";
Console.WriteLine(s);
s.Substring(0, 5);
Console.WriteLine(s);
Console.ReadLine();
C#の文字列は不変です。それを任意の文字列と連結すると、実際には新しい文字列、つまり新しい文字列オブジェクトが作成されます。しかし、StringBuilderは変更可能な文字列を作成します。