[解決済み] .NETで文字列はどのように渡されるのですか?
質問
を渡すと
string
を関数に渡すとき、文字列の内容へのポインタが渡されるのでしょうか、それとも文字列全体が
struct
のようにスタックで関数に渡されるのでしょうか?
どのように解決するのですか?
参照は渡されますが、技術的には 参照で渡されます。 これは微妙なことですが、非常に重要な違いです。次のコードを考えてみましょう。
void DoSomething(string strLocal)
{
strLocal = "local";
}
void Main()
{
string strMain = "main";
DoSomething(strMain);
Console.WriteLine(strMain); // What gets printed?
}
ここで起こることを理解するために必要なことが3つあります。
- 文字列はC#の参照型です。
- また、文字列は不変なので、文字列を変更しているように見えることをしても、そうではありません。全く新しい文字列が作成され、参照がそれに向けられ、古いものは捨てられる。
-
文字列が参照型であるにもかかわらず
strMain
は参照渡しではありません。それは 参照型です。 ですが、参照そのものは 値で渡される . パラメータを渡すときはいつでもref
キーワードを使わずにパラメータを渡した場合 (ただしout
パラメータを含まない)、値で何かを渡したことになります。
ということは、...参照を値で渡しているということでしょう。参照型なので、参照だけがスタックにコピーされました。しかし、どういうことでしょうか?
参照型を値で渡す。すでにやっていること
C#の変数は 参照型 または 値型 . C#のパラメータは 参照で渡される または 値で渡される . 用語が問題で、これらは同じもののように聞こえますが、そうではありません。
ANY型のパラメータを渡す場合、そのパラメータに
ref
キーワードを使用しない場合、それは値によって渡されます。値で渡した場合、実際に渡したのはコピーです。しかし、もしパラメータが参照型であったなら、コピーしたものは
参照です。
であり、それが何を指しているのかはわかりません。
の最初の行は以下の通りです。
Main
メソッドの最初の行です。
string strMain = "main";
この行では2つのものを作成しています: 値を持つ文字列
main
という参照変数が作成されました。
strMain
がそれを指しています。
DoSomething(strMain);
ここで、その参照を
DoSomething
. 値で渡しているので、コピーを作成したことになります。これは参照型なので、文字列そのものではなく、参照をコピーしたことを意味します。これで2つの参照ができ、それぞれがメモリ内の同じ値を指しています。
着信側の内部
ここでは、先頭の
DoSomething
メソッドを使用しています。
void DoSomething(string strLocal)
いいえ
ref
キーワードがないので
strLocal
と
strMain
は同じ値を指している2つの異なる参照です。を再割り当てすると
strLocal
...
strLocal = "local";
...保存されている値を変更したわけではありません。
strLocal
という参照を取り出し、全く新しい文字列に向けています。どうなるかというと
strMain
はどうなるのでしょうか?
何も起きません。古い文字列を指し示したままです。
string strMain = "main"; // Store a string, create a reference to it
DoSomething(strMain); // Reference gets copied, copy gets re-pointed
Console.WriteLine(strMain); // The original string is still "main"
不変性
ちょっとシナリオを変えてみましょう。文字列ではなく、あなたが作成したクラスのような変更可能な参照型を扱っていると想像してください。
class MutableThing
{
public int ChangeMe { get; set; }
}
もし、あなたが
に従う
を参照してください。
objLocal
を指しているオブジェクトのプロパティを変更することができます。
void DoSomething(MutableThing objLocal)
{
objLocal.ChangeMe = 0;
}
まだ1つしかない
MutableThing
はまだ一つしかなく、コピーされた参照と元の参照の両方がまだそれを指しています。
のプロパティは
MutableThing
自体が変更され
:
void Main()
{
var objMain = new MutableThing();
objMain.ChangeMe = 5;
Console.WriteLine(objMain.ChangeMe); // it's 5 on objMain
DoSomething(objMain); // now it's 0 on objLocal
Console.WriteLine(objMain.ChangeMe); // it's also 0 on objMain
}
あ、でも文字列はイミュータブル! また
ChangeMe
プロパティを設定することはできません。できないのは
strLocal[3] = 'H'
のように、C#ではC言語の
char
の配列のように、全く新しい文字列を構築する必要があります。唯一の変更方法は
strLocal
を変更する唯一の方法は、参照を別の文字列に向けることであり、それはつまり、あなたが
strLocal
影響を与えることができる
strMain
. 値は不変であり、参照はコピーである。
参照による参照の受け渡し
違いがあることを証明するために、次のようなことが起こります。 を参照渡しする場合です。
void DoSomethingByReference(ref string strLocal)
{
strLocal = "local";
}
void Main()
{
string strMain = "main";
DoSomethingByReference(ref strMain);
Console.WriteLine(strMain); // Prints "local"
}
このとき、文字列は
Main
の文字列は、スタック上にコピーすることなく参照を渡したため、本当に変更されてしまいます。
つまり、文字列が参照型であっても、値で渡すということは、呼び出し側で何が起ころうとも呼び出し側の文字列に影響を与えないということです。しかし、文字列は は 参照型であるため、文字列を渡すときにメモリ内の文字列全体をコピーする必要はありません。
さらなるリソース
- 以下は、私が読んだ中で最も優れた記事です。 C# における参照型と値型の違いについてです。 と、参照型が参照渡しのパラメーターと同じでない理由です。
- いつものように、Eric Lippert も に関するいくつかの優れたブログ記事 .
- 彼は 不朽の名作をいくつか持っています。 も持っています。
関連
-
[解決済み] VB.NETでプログラムパスを取得する?
-
[解決済み] AndroidでWCFサービスを利用する方法
-
[解決済み] JavaScriptで文字列が部分文字列を含むかどうかを確認する方法は?
-
[解決済み] バイトを文字列に変換する
-
[解決済み] JavaScriptで複数行の文字列を作成する
-
[解決済み] 変数を参照渡しする方法を教えてください。
-
[解決済み] C#で文字列のエンコーディングを手動で指定せずに、一貫性のあるバイト表現を得るには?
-
[解決済み] Microsoft.ACE.OLEDB.12.0' プロバイダがローカルマシンに登録されていません。
-
[解決済み】JavaScriptで文字列の出現箇所をすべて置換する方法
-
[解決済み】JavaScriptの関数にデフォルトのパラメータ値を設定する
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み] CLSID {XXXX} を持つコンポーネントの COM クラスファクトリの取得は、次のエラーにより失敗しました: 80040154。
-
[解決済み] app.configのマッピングがないアセンブリのapp.configの再マッピングを考慮する。
-
[解決済み] <Database> コンテキストを支えるモデルが、データベース作成後に変更されました。
-
[解決済み] WCF エラーの解決。このサービスのメタデータパブリッシングは現在無効になっています。
-
[解決済み] Html.BeginForm()にCSSクラスを追加する。
-
[解決済み] csilogfileは何のためにあるのですか?
-
[解決済み] ファイルまたはアセンブリをロードできませんでした 操作がサポートされていません。(HRESULT: 0x80131515 からの例外)
-
[解決済み] CryptographicException「キーセットが存在しない」、ただしWCF経由に限る
-
[解決済み] 文字列から数字を抽出する正規表現
-
[解決済み] SecureStringをSystem.Stringに変換する方法は?