web-dev-qa-db-ja.com

実行時のrefとoutの違いは何ですか?

C#はrefおよびoutキーワードを提供して、参照によって渡される引数を作成します。 2つの意味は非常に似ています。唯一の違いは、フラグ付き変数の初期化です。

  • refでは、変数を関数に渡す前に初期化する必要がありますが、outでは初期化しません。
  • outでは関数内で変数を初期化する必要がありますが、refでは初期化しません。

これら2つのキーワードの使用例もほとんど同じで、使用頻度が高すぎるため、コードのにおいだと考えられます(TryParseおよびTryGetValueパターンのような有効な使用例があります)。

これのために誰かが説明する可能性があるため、C#に非常に狭いユースケース用の2つの非常に類似したツールがあるのはなぜですか?

また、 [〜#〜] msdn [〜#〜] では、実行時の動作が異なると記載されています。

Refキーワードとoutキーワードは実行時の動作が異なりますが、コンパイル時にはメソッドシグネチャの一部とは見なされません。

実行時の動作はどのように異なりますか?

結論

どちらの答えも正しいようですが、両方ありがとうございます。私は jmoreno を受け入れました。

15
Gábor Angyal

この質問が行われたとき、MSDNの記事は微妙に正しくありませんでした( 修正されたため となっています)。 「異なる動作を引き起こす」ではなく、「異なる動作が必要」であるべきです。

特に、同じメカニズム(IL)を使用して動作を有効にしても、コンパイラーは2つのキーワードに異なる要件を適用します。

10
jmoreno

ここにあなたの質問に答えるかもしれないトピックに関する興味深い記事があります:

http://www.dotnetperls.com/ref

興味のあるポイント:

「refとoutの違いは、共通言語ランタイムではなく、C#言語自体にあります。」

更新:

私の仕事の上級開発者は@jmorenoの答えを裏付けたばかりなので、必ず読んでください!。

4
Dan Beaulieu

ランタイム?まったくありません。 refまたはoutキーワードのみが異なる同じパラメーターを持つメソッドをオーバーロードすることはできません。

これをコンパイルしようとすると、「同じシグネチャを持つメソッドがすでに宣言されています」というコンパイルエラーが発生します。

    private class MyClass
    {
        private void DoSomething(out int param)
        {
        }
        private void DoSomething(ref int param)
        {
        }
    }

この質問に答えるには: "... C#に非常に類似した2つの非常に類似したツールがあり、用途が狭いのですか?"

コードの可読性とAPIの観点からは、大きな違いがあります。 APIのコンシューマーとして、「out」が使用されている場合、APIはoutパラメーターに依存しないことを知っています。 API開発者として私は「out」を好み、絶対に(まれに)必要な場合にのみ「ref」を使用します。すばらしい議論についてはこのリファレンスを参照してください:

https://stackoverflow.com/questions/1516876/when-to-use-ref-vs-out

サポート情報:次のメソッドをコンパイルして逆アセンブルしました。 refキーワードとoutキーワード(この例ではout)を使用しましたが、アセンブリコードは、アドレス参照を除いて変更されませんでした。

    private class MyClass
    {
        internal void DoSomething(out int param)
        {
            param = 0;
        }
    }

00000000プッシュebp
00000001 mov ebp、esp
00000003 Push edi
00000004 Push esi
00000005 Push ebx
00000006 sub esp、34時間
00000009 xor eax、eax
0000000b mov dword ptr [ebp-10h]、eax
0000000e mov dword ptr [ebp-1Ch]、eax
00000011 mov dword ptr [ebp-3Ch]、ecx
00000014 mov dword ptr [ebp-40h]、edx
00000017 cmp dword ptr ds:[008B1710h]、0
0000001e je 00000025
00000020コール6E6B601E
00000025 nop
param = 0;
00000026 mov eax、dword ptr [ebp-40h]
00000029 xor edx、edx
0000002b mov dword ptr [eax]、edx
}
0000002d nop
0000002e lea esp、[ebp-0Ch]
00000031 pop ebx
00000032 pop esi
00000033 pop edi
00000034 pop ebp
00000035 ret

アセンブリを正しく読んでいますか?

2
Shmoken