323

オブジェクトをメソッドに渡す場合、ref キーワードを使用する必要があるのはなぜですか? とにかくこれはデフォルトの動作ではありませんか?

例えば:

class Program
{
    static void Main(string[] args)
    {
        TestRef t = new TestRef();
        t.Something = "Foo";

        DoSomething(t);
        Console.WriteLine(t.Something);
    }

    static public void DoSomething(TestRef t)
    {
        t.Something = "Bar";
    }
}


public class TestRef
{
    public string Something { get; set; }
}

出力は、オブジェクトが参照として渡されたことを意味する "Bar" です。

4

10 に答える 10

325

refオブジェクトが何であるかを変更したい場合は、 a を渡します。

TestRef t = new TestRef();
t.Something = "Foo";
DoSomething(ref t);

void DoSomething(ref TestRef t)
{
  t = new TestRef();
  t.Something = "Not just a changed t, but a completely different TestRef object";
}

DoSomething を呼び出した後t、元の を参照せずnew TestRef、まったく別のオブジェクトを参照します。

これは、 a などの不変オブジェクトの値を変更する場合にも役立ちますstringstring一度作成した a の値を変更することはできません。しかし、 を使用するrefことで、文字列を異なる値を持つ別の文字列に変更する関数を作成できます。

必要でない限り使用するのは得策ではありませんref。を使用refすると、メソッドは引数を別のものに自由に変更できます。メソッドの呼び出し元は、この可能性を確実に処理するようにコーディングする必要があります。

また、パラメーターの型がオブジェクトの場合、オブジェクト変数は常にオブジェクトへの参照として機能します。これは、refキーワードが使用されると、参照への参照があることを意味します。これにより、上記の例で説明したようなことができます。ただし、パラメーターの型がプリミティブ値 ( などint) の場合、このパラメーターがメソッド内で割り当てられている場合、渡された引数の値は、メソッドが返された後に変更されます。

int x = 1;
Change(ref x);
Debug.Assert(x == 5);
WillNotChange(x);
Debug.Assert(x == 5); // Note: x doesn't become 10

void Change(ref int x)
{
  x = 5;
}

void WillNotChange(int x)
{
  x = 10;
}
于 2008-10-09T11:52:51.647 に答える
95

「値による参照の受け渡し」と「参照によるパラメータ/引数の受け渡し」を区別する必要があります。

この話題がニュースグループに出てくるたびに注意深く書く必要がないように、私はこの件に関してかなり長い記事を書いた.

于 2008-10-09T12:02:32.547 に答える
62

.NET では、パラメーターをメソッドに渡すと、コピーが作成されます。値型では、値に加えた変更はすべてメソッド スコープにあり、メソッドを終了すると失われることを意味します。

参照型を渡すと、コピーも作成されますが、これは参照のコピーです。つまり、メモリ内に同じオブジェクトへの 2 つの参照があります。そのため、参照を使用してオブジェクトを変更すると、変更されます。ただし、参照自体を変更すると (これはコピーであることを覚えておく必要があります)、メソッドを終了すると変更も失われます。

人々が以前に言ったように、割り当ては参照の変更であるため、失われます。

public void Method1(object obj) {   
 obj = new Object(); 
}

public void Method2(object obj) {  
 obj = _privateObject; 
}

上記のメソッドは元のオブジェクトを変更しません。

あなたの例を少し修正

 using System;

    class Program
        {
            static void Main(string[] args)
            {
                TestRef t = new TestRef();
                t.Something = "Foo";

                DoSomething(t);
                Console.WriteLine(t.Something);

            }

            static public void DoSomething(TestRef t)
            {
                t = new TestRef();
                t.Something = "Bar";
            }
        }



    public class TestRef
    {
    private string s;
        public string Something 
        { 
            get {return s;} 
            set { s = value; }
        }
    }
于 2008-10-09T12:02:46.820 に答える
18

TestRef はクラス (参照オブジェクト) であるため、ref として渡さずに t 内の内容を変更できます。ただし、t を ref として渡すと、TestRef は元の t が参照するものを変更できます。つまり、別のオブジェクトを指すようにします。

于 2008-10-09T11:53:32.707 に答える
17

refあなたが書くことができます:

static public void DoSomething(ref TestRef t)
{
    t = new TestRef();
}

そして、メソッドが完了した後に t が変更されます。

于 2008-10-09T11:52:37.433 に答える
7

foo参照型 ( など)の変数 ( など) は、「Object #24601」という形式のオブジェクト識別子List<T>を保持していると考えてください。このステートメントが"Object #24601" (4 つの項目を持つリスト) を保持するとします。次に、呼び出しによって Object #24601 にその長さが尋ねられ、4 と応答するため、4 に等しくなります。foo = new List<int> {1,5,7,9};foofoo.Lengthfoo.Length

fooを使用せずに をメソッドに渡すと、そのメソッドはオブジェクトref#24601 を変更する可能性があります。このような変更の結果、 はfoo.Length4 に等しくなくなる可能性があります。ただし、メソッド自体は を変更できず、foo「オブジェクト #24601」を保持し続けます。

fooパラメータとして渡すとref、呼び出されたメソッドは Object #24601 だけでなく、fooそれ自体にも変更を加えることができます。このメソッドは、新しいオブジェクト #8675309 を作成し、それへの参照を に保存する場合がありますfoo。その場合、foo"Object #24601" は保持されなくなりますが、代わりに "Object #8675309" が保持されます。

実際には、参照型変数は「Object #8675309」という形式の文字列を保持しません。意味のある数値に変換できるものさえ保持していません。各参照型変数は何らかのビット パターンを保持しますが、そのような変数に格納されているビット パターンとそれらが識別するオブジェクトとの間に固定された関係はありません。コードがオブジェクトまたはそれへの参照から情報を抽出し、別の参照が同じオブジェクトを識別したかどうかを後で判断する方法はありません。コードが元のオブジェクトを識別する参照を保持または認識していない限りです。

于 2015-07-17T16:30:51.860 に答える
5

これは、C でポインターをポインターに渡すようなものです。.NET では、元の T が参照するものを変更できますが、個人的には、.NET でそれを行っている場合は、おそらく設計上の問題があると思います!

于 2008-10-09T11:58:03.070 に答える
4

参照型でキーワードを使用することによりref、参照への参照を効果的に渡します。多くの点でキーワードの使用と同じですが、メソッドが実際に'ed パラメーターoutに何かを割り当てるという保証がないという小さな違いがあります。ref

于 2008-10-09T11:53:39.977 に答える
3

ref次の 2 つのスコープのグローバル エリアとして模倣 (または動作) します。

  • 発信者
  • 呼び出し先。
于 2015-05-10T20:55:07.337 に答える
1

ただし、値を渡す場合は事情が異なります。値を強制的に参照渡しすることができます。これにより、たとえば整数をメソッドに渡し、そのメソッドに代わりに整数を変更させることができます。

于 2008-10-09T11:51:31.227 に答える