12

ご存知のとおり、C#クラスオブジェクトは参照として扱われるので、参照オブジェクトをメソッドへの参照として渡すとどうなりますか?私たちが持っていると言う:

public class A { ... }

その後:

public void F(ref A a) { ... }

コンパイラは、それaがすでに参照型であることを検出してそのように保持しますか、それともそのオブジェクトへの新しい参照を作成しますか?

そして、このようなものがある場合はどうなりますか?

public void F(ref A a)
{
    F(ref a);
}

このコードでは、明らかなことに加えてStackOverflowException、コンパイラは参照への参照を作成しますか...a参照オブジェクトはどれを参照しますか?

4

6 に答える 6

28

これは、例で最もよく示されています。

public class C { public int P { get; set; } }
public class X
{
    static void M(C c1, C c2, ref C c3, ref C c4)
    {
      c1.P = 11;
      c2 = new C() { P = 12 };
      c3.P = 13;
      c4 = new C() { P = 14 };
    }
    static void Main()
    {
      C q1 = new C() { P = 1 };
      C q2 = new C() { P = 2 };
      C q3 = new C() { P = 3 };
      C q4 = new C() { P = 4 };
      M(q1, q2, ref q3, ref q4);
      Console.WriteLine(q1.P);
      Console.WriteLine(q2.P);
      Console.WriteLine(q3.P);
      Console.WriteLine(q4.P);
    }
}

何が起こるのですか?

q1とc1は同じオブジェクトを参照しますが、変数は異なります。c1.Pを変更すると、両方の変数が同じオブジェクトを参照するため、q1.Pが変更され、q1は11になります。

q2とc2は同じオブジェクトを参照しますが、変数は異なります。c2とq2は異なる変数であるため、c2を変更してもq2は変更されません。一方を変更しても、もう一方は変更されません。q2は2のままで、新しいオブジェクトは失われます。

q3とc3は同じ変数の2つの名前であるため、同じオブジェクトを参照します。同じものの2つの名前であるため、q3.Pを自動的に変更するc3.Pを変更すると。

q4とc4は同じ変数の2つの名前であるため、q4を変更するとc4も変更されます。

それは理にかなっていますか?

「この変数のエイリアスを作成する」のキーワードが「ref」であるのは残念です。それが「エイリアス」であったなら、それはもっと明確だっただろう。

2番目の質問に答えるには:いいえ、これは一連の参照を作成しません。より明確な例を見てみましょう。

...
int c1 = 123;
M(ref c1);
...
void M1(ref int q1) { M2(ref q1); }
void M2(ref int q2) { M2(ref q2); }

つまり、c1とq1は同じ変数の異なる名前であり、q1とq2は同じ変数の異なる名前であるため、c1、q1、およびq2はすべて相互のエイリアスです。C ++のように、C#には「変数への参照への参照」はありません。

于 2013-03-10T22:23:07.793 に答える
4

のような呼び出しで

F(ref a);   // ByRef parameter

変数aは、メソッドの本体によって「直接使用」されFます。保管場所は1つだけです。メソッドFがそのパラメーターに割り当てた場合、その割り当ては、を見ることができるすべての人aにすぐに表示されます。逆に、メソッドの実行中に誰か(外部F)が割り当てた場合、のパラメータは「突然」新しいオブジェクトに変更されます。aFF

一方、のような呼び出しで

F(a);  // normal value parameter

変数aは最初に新しい変数にコピーされ、次に新しい変数が内部で使用されFます。ここで、のパラメーターの型がF(astructenum)の場合、コピーは値によって行われます。したがって、データ全体がコピーされます。ただし、パラメーターの型が参照型class(配列型を含む)、、interfacedelegateの場合、のコピーには参照のコピーaのみが含まれます。

型パラメーターを使用した値パラメーターの場合の理解を確認するには、classこれらのメソッドが何をするかを理解してください。

static void F1(List<int> list>)  // no ref modifier
{
    list.Clear();
}

static void F2(List<int> list>)  // no ref modifier
{
    list = new List<int>();
}

これはおそらく興味深い例refです:

static void G(ref string a, ref string b)
{
    if (string.Equals(a, b))
        b += "_unique";

    // Is it now safe to say that a and b are distinct?
    // No. Anyone could have changed either a or b by now.
    // For example, a and b could "alias" public fields visisble to other threads.
}

上記の使用例として、メソッド内で一緒に変更されるGコードvar x = "initial"; G(ref x, ref x);を考えてみましょう。abG

于 2013-03-10T22:43:13.333 に答える
3

ref元の値への参照を作成するだけです。「値」が変数のメモリの場所である参照型の場合。このメソッドを使用するrefと、元の変数の参照内容を変更できるようになりました。次に、すでにref2番目のメソッドである引数を使用して同じことを行うと、最初のメソッドが行ったのと同じ参照があります。

于 2013-03-10T22:26:05.887 に答える
2

メソッドのパラメーターとしてオブジェクトを渡すときは、元のオブジェクトを参照する新しいポインターを渡します。オブジェクトをrefパラメーターとして渡す場合は、呼び出し元メソッドを使用するのと同じポインターを渡します。例、

public void F(ref A a, A b){
    a = new A(1);
    b.Property = 12;
    b = new B(2);
}

public void G(){
    A a = new A(0);
    A b = new A(0);
    F(a,b);
    System.Console.WriteLine(a + " - " + b);
}

オブジェクトbのポインタは変更されませんが、元のオブジェクトは変更されるため、出力は1〜12になります。

于 2013-03-10T22:20:58.420 に答える
2

2つの概念は同じではありません。メソッドパラメータは、値型か参照型かに関係なく、refによって変更できます。

参照によって型を渡すと、呼び出されたメソッドは、パラメーターによって参照されるオブジェクトを変更したり、パラメーターの保管場所を変更したりできます。

static void Main()
{
    Foo item = new Foo("aaa");
    GetByReference(ref item);
    Console.WriteLine(item.Name)
}
static void ChangeByReference(ref Foo itemRef)
{
    itemRef = new Foo("bbb");
}

この場合、オブジェクトの値は変更していませんが、オブジェクト自体を変更したため、これは実際には「bbb」を出力します。

于 2013-03-10T22:18:02.133 に答える
1

簡単に言うと、変数をrefパラメーターとして渡すことは、元の変数のエイリアスを作成するようなものです。

参照型と参照パラメーターは別個のエンティティです。C#では、変数は常に値で渡されます。その値は、別のオブジェクトへの参照または保存された値である可能性があります。

つまり、オブジェクトインスタンスをメソッドに渡すと、メソッドがオブジェクトインスタンスへの参照を取得するため、参照型は「参照によって渡されます」。
参照パラメーターの場合、参照は変数への参照です(したがって、これをエイリアスと考えるのが理にかなっています)。これは、「参照による受け渡し」の別の形式です。

あなたの例で行く:

public void F(ref A a)
{
    F(ref a);
}

ここでは、a無限に参照される単一のオブジェクト(元のパラメーター)があるようです。(これは実際に起こることではないことに注意してください)。この図は、参照パラメーターを処理するときに内部で何が起こるかを慣用的に表現することを目的としています。

ここに画像の説明を入力してください

詳細については、4.0 C#仕様のセクション1.6.6.1を参照してください。

于 2013-03-10T22:10:02.193 に答える