9

これが私がこれまでに理解していることです:

値渡し

値渡しとは、引数のコピーが渡されることを意味します。そのコピーを変更しても、オリジナルは変更されません。

参照渡し

参照渡しとは、オリジナルへの参照が渡されることを意味します。参照への変更はオリジナルに影響します。

REF キーワード

REF は、関数に入る前にオブジェクトが初期化されることをコンパイラに伝えます。REF は、値がすでに設定されていることを意味します。したがって、メソッドはそれを読み取って変更できます。REF は、インとアウトの 2 つの方法です。

OUT キーワード

OUT は、オブジェクトが関数内で初期化されることをコンパイラーに伝えます。OUT は値がまだ設定されていないことを意味するため、return を呼び出す前に設定する必要があります。OUT は一方向のみです。

質問

では、どのシナリオで ref キーワードと out キーワードの使用を、参照渡しまたは値渡しと組み合わせますか? 例は非常に役立ちます。

大変助かります。

4

7 に答える 7

20

1つのパラメータを組み合わせることは決してありません。どちらも「参照渡し」を意味します。refout

もちろん、refパラメーターとoutパラメーターを1つのメソッドで組み合わせることができます。

refとの違いoutは主に意図にあります。refは双方向のデータ転送を通知し、outは一方向を意味します。

しかし、意図に加えて、C#コンパイラは明確な割り当てを追跡し、それが最も顕著な違いを生みます。また、outパラメータの誤用(読み取り)を防ぎます。

void SetOne(out int x) 
{
  int y = x + 1; // error, 'x' not definitely assigned.
  x = 1;         // mandatory to assign something
}

void AddTwo(ref int x)
{
    x = x + 2;  // OK, x  is known to be assigned
}

void Main()
{
    int foo, bar;

    SetOne(out foo); // OK, foo does not have to be assigned
    AddTwo(ref foo); // OK, foo assigned by SetOne
    AddTwo(ref bar); // error, bar is unassigned
}
于 2009-11-05T20:38:07.240 に答える
8

よろしくお願いします

言語を正しく注意深く使用することで、理解が深まります。

値による受け渡しは、引数のコピーが渡されることを意味します。

はい、これは正確です。

そのコピーを変更しても、元のコピーは変更されません。

ではない正確に。変数を注意深く区別することから始めます。検討:

class Foo { public int x; }
...
void N() 
{
  Foo blah = new Foo();
  blah.x = 0;
  M(blah);
}
...
void M(Foo foo)
{
  foo.x = 123; // changes blah.x
  foo = null; // does not change blah
}

ここでの変数はx、blah、fooです。xはフィールド、blahはローカル、fooは正式なパラメーターです。

ここでの値はnull、0、123、およびFooのインスタンスへの参照です。 その参照は値です。この事実を理解することが重要です。

変数blahの値を変数fooにコピーすることにより、blahの値のコピーが渡されます。blahの値は、Fooのインスタンスへの参照です。

MにはFooへの参照であるblahの値のコピーがあるため、Mは変数xの値を変更できます。Mがfooの内容をnullに変更しても、それはblahを変更しません。fooには、blahの値のコピーが含まれています。

参照による受け渡しとは、オリジナルへの参照が渡されることを意味します。

言葉遣いは慎重に選んでください。「オリジナル」とは何ですか?

これは、「参照による受け渡しとは、変数でなければならない引数への参照が渡されることを意味します」とより適切に表現されます。それについて考えるより簡単な方法は、「参照によって渡すと、パラメーターが引数として渡される変数のエイリアスになる」ということです。

参照への変更はオリジナルに影響します。

パラメータと引数は相互のエイリアスであるため、参照への変更が元の値に影響を与えるわけではありません。参照はオリジナルです。これらは両方とも同じ変数です

REFは、関数に入る前にオブジェクトが初期化されることをコンパイラーに通知します。

「オブジェクト」は無意味です。あなたは「変数」を意味します。

「ref」は「変数が初期化されていることをコンパイラに通知」しません。むしろ、「ref」はコンパイラに「あなた、コンパイラは、変数が初期化されていることを確認する必要があります」と伝えます。それはかなり違います!

REFは、値がすでに設定されていることを意味します。

いいえ、refでは変数がすでに設定されている必要があります。「値を設定する」などというものはありません。

したがって、メソッドはそれを読み取って変更できます。

「それ」とは「変数」を意味します。

REFは、インとアウトの2つの方法です。

正しい。

OUTは、オブジェクトが関数内で初期化されることをコンパイラーに通知します。

「変数」を意味する「オブジェクト」の使用をやめます。まったく異なることを混乱させないようにすれば、物事をより明確に理解できるようになります。変数はオブジェクトではありません。変数は保存場所であり、その一部にはが含まれている場合があり、それらの値の一部はオブジェクトへの参照である場合があります。

したがって、outは、変数がメソッド内で初期化されることをコンパイラーに通知します。そうですが、それは正しくありません。メソッドが例外をスローしたり、メソッドが無限ループに入ったりする場合を忘れています。これらも正当なシナリオです。

OUTは、値がまだ設定されていないことを意味します。

繰り返しますが、「値」とは「変数」を意味します。しかし、これは正確ではありません。初期化された変数を「out」パラメーターとして渡すことは完全に合法です。無意味ですが、合法です。

したがって、returnを呼び出す前に設定する必要があります。

「return」は呼び出されません。メソッドが呼び出されます。しかし、はい、メソッドは正常に戻る前に変数に値を割り当てる必要があります。

OUTは一方向のみであり、それはアウトです。

右。

したがって、どのシナリオでrefキーワードとoutキーワードの使用を組み合わせますか

そのようなシナリオはありません。

于 2009-11-05T21:34:23.583 に答える
1

編集: この回答を修正して、C#の「out」キーワードが期待どおりに機能しないことを反映しました(たとえば、コンピューターサイエンスの意味での真のOUTパラメーター)。私は当初、「out」は値OUTを渡すと述べましたが、間違っていることが証明されました。

'out'と'ref'を一緒に使用することはできません。C#(NET Framework)には3つの呼び出し規約があります。

  • キーワードなし=値渡し(IN)
  • 'out'キーワード=呼び出し前に明確な割り当て要件なしで参照渡し(REF)
  • 'ref'キーワード=呼び出し前に明確な割り当て要件を持つ参照渡し(REF)

C#には、真のOUTまたはIN-OUTパラメーター機能はありません。

C#の「out」パラメーターが真のOUTパラメーターではないことを確認するには、次のコードを使用できます。

  public class Test
  {
    Action _showValue;

    public void Run()
    {
      string local = "Initial";
      _showValue = () => { Console.WriteLine(local.ToString()); };

      Console.WriteLine("Passing by value");
      inMethod(local);

      Console.WriteLine("Passing by reference with 'out' keyword");
      outMethod(out local);

      Console.WriteLine("Passing by reference with 'ref' keyword");
      refMethod(ref local);

    }

    void inMethod(string arg)
    {
      _showValue();
      arg = "IN";
      _showValue();
    }

    void outMethod(out string arg)
    {
      _showValue();
      arg = "OUT";
      _showValue();
    }

    void refMethod(ref string arg)
    {
      _showValue();
      arg = "REF";
      _showValue();
    }
  }

出力は次のとおりです。

Passing by value
Initial
Initial
Passing by reference with 'out' keyword
Initial
OUT
Passing by reference with 'ref' keyword
OUT
REF

ご覧のとおり、「out」と「ref」の両方が実際にはREFを通過します。唯一の違いは、コンパイラが明確な割り当ての目的でそれらを処理する方法にあります。

于 2009-11-05T20:39:25.087 に答える
1

どちらの方法でも通過するダイナミクスを理解しています。一部のパラメーター シナリオは次のとおりです。

  • ref int numin/out パラメータ用。関数その値を変更する場合があります。
  • out int numref のように、関数は戻る前にそれに値を割り当てる必要があります。

一般に、出力パラメーターは、関数が複数の値を返す必要がある場合に適しています。これは、関数の戻り値が 1 つしかないためです (ただし、複合することはできます)。

一部の ADO.NET メソッドなどのデータ アクセス プロバイダーは、出力パラメーターを使用して情報を返すことがあります。一部のデータ アクセス方法は、in/out パラメータを持つデータベース ストアド プロシージャを模倣しています。

編集:参照型の 1 つの規定は、パラメーターref StringBuilder wordまたはStringBuilder word(値によって) 同じように動作することです。その時点でフォーカスは参照であり、ヒープ上の値ではないため、基になる実装はわずかに異なる場合がありますが、外部の文字列が影響を受けます。

于 2009-11-05T20:43:31.623 に答える
0

別の関数で読み書きしたいものをrefで渡すので、正しく読み取られるように初期化された変数を渡す必要があります。

編集:例:

void mymethod(ref int a) {
  a++;
}

別の関数で書き込みたいものをOUTとして渡しますが、関数で読み取られるのではなく、書き込まれるだけなので、初期化する必要はありません。

編集:例:

void mymethod2(out string a) {
  a="hello";
}
于 2009-11-05T20:38:33.917 に答える
0

OUT複数の値を返す必要があるメソッドがある場合、キーワードを使用すると便利です。たとえば、 のようなメソッドを見てくださいint.TryParse()

を使用するREFと、オブジェクトの明示性が向上します。メソッドに渡される非プリミティブは、本質的に参照によって渡されることに注意してください。通常のマネージ コードでは、その必要性はあまりありません。REF キーワードを宣言することにより、パラメーターがメソッドの本体で変更される可能性が高いため、呼び出し元のコードがそれを認識する必要があることを示しています (したがってref、呼び出し元のコードにも明示的に を追加する必要があります。

于 2009-11-05T20:41:52.983 に答える
0

C++ を理解している場合、これが役立つかもしれません。

void Foo(Bar) {} // pass by value c# (if it's a value type ;))
void Foo(Bar) {} // c++

void Foo(Bar) {} // pass by reference c# (if it's a reference type ;))
void Foo(Bar&) {} // c++

void Foo(ref Bar) {} // c#
void Foo(Bar*) // c++

void Foo(out Bar) {} // c#
void Foo(Bar**) {} // c++ (the contents of *Bar needs to be filled up)
于 2009-11-05T20:47:22.690 に答える