112

プログラムのメモリ内状態であるオブジェクトがあり、状態を変更するためにオブジェクトを渡す他のワーカー関数もいくつかあります。私はそれをrefでワーカー関数に渡しています。しかし、私は次の機能に出くわしました。

byte[] received_s = new byte[2048];
IPEndPoint tmpIpEndPoint = new IPEndPoint(IPAddress.Any, UdpPort_msg);
EndPoint remoteEP = (tmpIpEndPoint);

int sz = soUdp_msg.ReceiveFrom(received_s, ref remoteEP); 

received_sとの両方remoteEPが関数から何かを返しているため、混乱します。が必要でremoteEP必要がないのはなぜですか?refreceived_s

私はACプログラマーでもあるので、頭からポインターを取り出すのに問題があります。

編集: C# のオブジェクトは内部のオブジェクトへのポインターのようです。したがって、オブジェクトを関数に渡すと、ポインターを介してオブジェクトの内容を変更できます。関数に渡されるのはオブジェクトへのポインターだけであるため、オブジェクト自体はコピーされません。ダブルポインターのような関数で新しいオブジェクトを切り替えたり作成したりできるようにする場合は、ref または out を使用します。

4

8 に答える 8

234

簡単な答え:引数の受け渡しに関する私の記事を読んでください。

長い答え: 参照型パラメーターが値で渡される場合、オブジェクトのコピーではなく、参照のみが渡されます。これは、C または C++ で (値によって) ポインターを渡すようなものです。パラメーター自体の値の変更は呼び出し元には表示されませんが、参照が指すオブジェクトの変更は表示れます。

パラメーター (任意の種類) が参照によって渡される場合、それはパラメーターへの変更が呼び出し元に表示されることを意味します。つまり、パラメーターへの変更は変数への変更です。

もちろん、記事ではこれらすべてをより詳細に説明しています:)

有用な答え: ref/out を使用する必要はほとんどありません。これは基本的に別の戻り値を取得する方法であり、メソッドがおそらくやりすぎていることを意味するため、通常は避ける必要があります。常にそうであるとは限りません (TryParseなどは の合理的な使用の標準的な例ですout) が、ref/out の使用は比較的まれなはずです。

于 2009-03-11T19:11:07.743 に答える
27

非 ref パラメーターはポインターであり、ref パラメーターは double ポインターであると考えてください。これが一番助かりました。

ref で値を渡すことはほとんどありません。相互運用性の問題がなければ、.Net チームはそれを元の仕様に含めなかっただろうと思います。ref パラメーターが解決するほとんどの問題に対処するオブジェクト指向の方法は、次のとおりです。

複数の戻り値の場合

  • 複数の戻り値を表す構造体を作成する

メソッド呼び出しの結果としてメソッド内で変更されるプリミティブの場合(メソッドにはプリミティブ パラメーターに対する副作用があります)

  • メソッドをインスタンス メソッドとしてオブジェクトに実装し、メソッド呼び出しの一部としてオブジェクトの状態 (パラメーターではない) を操作します。
  • 複数の戻り値ソリューションを使用して、戻り値を状態にマージします
  • メソッドで操作できる状態を含むオブジェクトを作成し、プリミティブ自体ではなく、そのオブジェクトをパラメーターとして渡します。
于 2009-03-11T19:20:32.400 に答える
13

おそらく、C# アプリ全体を作成し、ref でオブジェクト/構造体を渡さないようにすることもできます。

こんなことを言っていた教授がいました。

refs を使用する唯一の場所は、次のいずれかの場所です。

  1. 大きなオブジェクト (つまり、オブジェクト/構造体の内部にオブジェクト/構造体が複数のレベルにある) を渡したい場合、それをコピーするとコストがかかり、
  2. フレームワーク、Windows API、またはそれを必要とするその他の API を呼び出しています。

できるからといってやらないでください。パラメータの値を変更し始めて注意を払わないと、いくつかの厄介なバグに悩まされる可能性があります。

私は彼のアドバイスに同意し、学校からの 5 年以上の間、Framework や Windows API を呼び出す以外にそれが必要になったことは一度もありませんでした。

于 2009-03-11T20:06:07.860 に答える
3

received_s は配列であるため、その配列へのポインターを渡しています。この関数は、基になる場所やポインターを変更せずに、既存のデータをその場で操作します。ref キーワードは、実際のポインターをその場所に渡し、そのポインターを外部関数で更新することを意味するため、外部関数の値が変更されます。

たとえば、バイト配列は前後に同じメモリへのポインタであり、メモリは更新されたばかりです。

エンドポイントの参照は、実際には関数の外側のエンドポイントへのポインターを、関数の内側で生成された新しいインスタンスに更新しています。

于 2009-03-11T19:10:53.110 に答える
3

ref は、ポインターを参照渡しすることを意味すると考えてください。ref を使用しないということは、ポインタを値渡ししていることを意味します。

いっそのこと、私が今言ったことを無視して (特に値の型に関しては、おそらく誤解を招く可能性があります)、この MSDN ページを読んでください。

于 2009-03-11T19:11:13.967 に答える