ベストプラクティス:ByRefまたはByVal? .Netで
質問
ByRefとByValを選択する際に考慮すべき事項は何ですか。
この2つの違いは理解していますが、ByRefがリソースを節約するかどうか、または.Net環境でそれを心配する必要があるかどうかは完全にはわかりません。
ある状況で機能が重要でない場合、この2つをどのように決定しますか?
解決
これについては多くの誤った情報があります。主なことは、値の型と参照型の違いと、 値渡しと参照渡しの違い。
ほとんどの場合、値渡しを行います。参照渡しは、「渡されるリストに物事を追加するだけではなく、「複数の結果を返したい」の場合、ほぼ常に行われます。」 pass-by-referenceを使用するメソッドの古典的な例は、 Int32.TryParse ここで、戻り値は成功/失敗であり、解析された値は" returned&quot ;;出力パラメータによって。
他のヒント
デフォルトはすべての型のbyValueですが、「参照型」の2つのオプションの意味を理解することが重要です。 (クラス)値型ではなく。 (構造体)。
参照型の場合、メソッドで参照型変数を宣言すると、その変数はメソッドのスタックフレームのメモリ位置になります。ヒープ上にはありません。その変数を(新規またはファクトリなどを使用して)初期化すると、ヒープ上に実際のオブジェクトが作成され、そのオブジェクトのアドレスがメソッドスタックフレームの宣言された参照変数に格納されます。
Valによって別のメソッドに参照型を渡すと、呼び出し元のメソッドスタックに格納されているアドレスのコピーを作成し、その値のコピー(ポインターアドレス)を呼び出されたメソッドに渡します。呼び出されたメソッドスタック内の新しいメモリスロット。呼び出されたメソッド内で、新しいクローン変数は、ヒープ上の同じオブジェクトを直接ポイントします。そのため、同じオブジェクトのプロパティを変更できます。ただし、元の参照変数(呼び出し元メソッドスタック上)が指すヒープオブジェクトを変更することはできません。 呼び出されたメソッドで私が書いた場合
myVar = new object();
呼び出し元のメソッドの元の変数は、新しいオブジェクトを指すように変更されません。
参照型byRef、otohを渡すと、呼び出し元メソッドスタック(ヒープ上のオブジェクトへのポインターを含む)で宣言された変数へのポインターを渡すため、オブジェクトへのポインターへのポインター。呼び出し元のメソッドスタック上のメモリ位置を指し、ヒープ上のオブジェクトを指します。
したがって、今度は、呼び出されたメソッドの変数の値を変更する場合、上記のように「objecte」に設定することにより、「参照」なので呼び出しメソッドの変数に、呼び出しメソッドの変数が指すオブジェクトを実際に変更しています。したがって、呼び出されたメソッドが戻ると、呼び出し元のメソッドの変数は、ヒープ上の同じ元のオブジェクトを指すことはなくなります。
ByValは「デフォルト」にする必要があります。 ByRefを使用する特別な理由がない限り、使用してください
.netでオブジェクトByValを渡すと、オブジェクトのコピーが作成されず、ByRefを超えるリソースは消費されません。ポインタは引き続き関数に渡されます。ランタイムは、関数内のポインターを変更して異なる値を返すことができないようにするだけです。オブジェクト内の値に変更を加えることができ、それらの変更は関数の外に表示されます。これが、ByRefの使用頻度が非常に低い理由です。関数が戻ってくる実際のオブジェクトを変更したい場合にのみ必要です。したがって、出力パラメーターです。
「ByRef」を使用;パラメータが「出力」の場合のみパラメータ。それ以外の場合は、「ByVal」を使用します。 " ByRef"の使用明示的に値を返すべきではないパラメーターでは危険であり、バグを簡単に生成できます。
ByRefは決して使用すべきではないと主張します。これは悪い習慣です。関数が(ByRefパラメーターを介して)複数の値を返すことを許可するという典型的なユースケースにも適用します。関数は、これらの複数の戻り値を含む構造化された応答を返す方がよいでしょう。関数がreturnステートメントを介してのみ値を返す場合、より明確で明確になります。
特定の引数をByRefとしてマークすると、その引数に割り当てられた変数が変更されることを関数のユーザーに示します。*****
すべての引数にByRefを使用する場合、どの変数が関数によって変更され、どの変数が単に読み取られるかを知る方法はありません。 (関数ソース内の覗き見は別として!)
Microsoftによると、ByValまたはByRefを選択すると、十分に大きい値のパフォーマンスに影響する可能性があります(値および参照による引数の受け渡し(Visual Basic)):
パフォーマンス。合格メカニズムはパフォーマンスに影響を与える可能性がありますが コードの違いは、通常、その違いはわずかです。 1つの例外 これには、ByValに渡される値型があります。この場合、Visual Basic 引数のデータ内容全体をコピーします。したがって、 構造体などの大きな値タイプ、より効率的に渡すことができる ByRefです。
[強調を追加]。
Sub last_column_process()
Dim last_column As Integer
last_column = 234
MsgBox last_column
trying_byref x:=last_column
MsgBox last_column
trying_byval v:=last_column
MsgBox last_column
End Sub
Sub trying_byref(ByRef x)
x = 345
End Sub
Sub trying_byval(ByRef v)
v = 555
End Sub
多くの混乱私は単純化しようとします。基本的に4つの選択肢があります:
- Valで値型を渡す
- 値型byRefを渡す
- Valでオブジェクトを渡す
- Refによるオブジェクトの受け渡し
byRefを使用しないでください決してと言う人もいます。それらは技術的には正しいですが、1つ確かなことがあります。 決してという単語を使用しないでください決して。システムをゼロから設計している場合、byRefはすべてのコストで回避する必要があります。これを使用すると、設計上の欠陥が明らかになります。ただし、既存のシステムでの作業では、優れた設計を実装するための柔軟性があまり得られない場合があります。時々、セッションを行う必要があります。つまり、byRefを使用します。たとえば、byRefを使用して2日間で修正を取得できる場合、車輪を再発明し、byRefの使用を避けるために同じ修正を取得するのに1週間かかるよりも好ましい場合があります。
概要:
- 値型でbyValを使用:関数に値を渡します。これが好ましい方法です デザイン関数。
- 値型でbyRefを使用:関数から複数の値を返すのに役立ちます。もし、あんたが に複数の値を返す必要がある関数を作成しています 既存のシステムでは、オブジェクトの作成(およびプロパティの設定と破棄)よりも優れている場合があります。 1つの関数に対して。
- オブジェクトでbyValを使用:オブジェクトのポインターを関数に渡します。関数は オブジェクトを変更します。
- オブジェクトでbyRefを使用する:オブジェクトのポインターへのポインターを関数に渡します。許可する 呼び出し元が指しているオブジェクトを変更します。これにより、 バグを見つけるのは難しく、それを使用する正当な理由は考えられません。 Doesntは存在しないことを意味しますが、存在する場合は少数です とはるかに。