.NET Frameworkが参照パラメーターを使用する方法と、文字列で何が起こるかをようやく理解したので、AdamHouldsworthに本当に感謝しています。
.NETには、次の2種類のデータ型があります。
- 値型:int、float、boolなどのプリミティブ型
- 参照型:文字列を含む他のすべてのオブジェクト
参照型の場合、オブジェクトはヒープに格納され、変数はこのオブジェクトを指す参照のみを保持します。参照を介してオブジェクトのプロパティにアクセスし、それらを変更できます。この変数の1つをパラメーターとして渡すと、同じオブジェクトを指す参照のコピーがメソッド本体に渡されます。したがって、プロパティにアクセスして変更すると、ヒープに格納されているのと同じオブジェクトが変更されます。つまり、このクラスは参照オブジェクトです。
public class ClassOne
{
public string Desc { get; set; }
}
あなたがこれをするとき
ClassOne one = new { Desc = "I'm a class one!" };
参照によって示されるヒープ上にオブジェクトがありますone
。これを行う場合:
one.Desc = "Changed value!";
ヒープ上のオブジェクトが変更されました。この参照をパラメーターとして渡す場合:
public void ChangeOne(ClassOne one)
{
one.Desc = "Changed value!"
}
one
ヒープ上の同じオブジェクトを指す元の参照のコピーを保持しているため、ヒープ上の元のオブジェクトも変更されます。
しかし、これを行う場合:
public void ChangeOne(ClassOne one)
{
one = new ClassOne { Desc ="Changed value!" };
}
元のオブジェクトは変更されていません。これone
は、参照のコピーが別のオブジェクトを指しているためです。
参照により明示的に渡す場合:
public void ChangeOne(ref ClassOne one)
{
one = new ClassOne { Desc ="Changed value!" };
}
one
このメソッドの内部には、外部参照のコピーではなく、参照自体が含まれているため、元の参照はこの新しいオブジェクトを指します。
文字列は不変です。これは、文字列を変更できないことを意味します。そうしようとすると、新しい文字列が作成されます。したがって、これを行う場合:
string s = "HELL";
s = s + "O";
2行目は、値が「HELLO」で「HELL」がヒープ上に破棄された(ガベージコレクションのために残された)文字列の新しいインスタンスを作成します。
したがって、次のようなパラメータとして渡すと、変更できません。
public void AppendO(string one)
{
one = one + "O";
}
string original = "HELL";
AppendO(original);
original
文字列はそのままです。関数内のコードは新しいオブジェクトを作成し、それを元の参照のコピーであるオブジェクトに割り当てます。しかし、オリジナルは「地獄」を指さし続けます。
値型の場合、それらがパラメーターとして関数に渡されると、値によって渡されます。つまり、関数は元の値のコピーを受け取ります。したがって、関数本体内のオブジェクトに加えられた変更は、関数外の元の値には影響しません。
問題は、文字列は参照型ですが、値型のように動作するように見えることです(これは、比較やパラメーターの受け渡しなどに適用されます)。
ref
ただし、上で説明したように、キーワードを使用して参照することにより、コンパイラーに参照型を渡すことができます。これは文字列でも機能します。
このコードを確認すると、文字列が変更されていることがわかります(これは、、またはその他の値型にも適用されますint
)float
。
public static class StringTest
{
public static void AppednO(ref string toModify)
{
toModify = toModify + "O";
}
}
// test:
string hell = "HELL";
StringTest.AppendO(ref hell);
if (hell == "HELLO")
{
// here, hell is "HELLO"
}
エラーを回避するために、パラメーターをrefとして定義する場合は、この修飾子を使用してパラメーターを渡す必要があることに注意してください。
とにかく、この場合(および同様の場合)は、より自然な機能構文を使用することをお勧めします。
var hell = StringTest.AppendO(hell);
(もちろん、この場合、関数にはこのシグネチャと対応する実装があります。
public static string AppendO(string value)
{
return value + "O";
}
文字列に多くの変更を加える場合は、「可変文字列」で機能するStringBuilderクラスを使用する必要があります。
文字列型のプロパティがどのように渡されるか