21

作成中のクラスに特定の連結リストを付与したい。クラスがそのリストに書き込むようにします (.addLast() などで)。

refそのためにキーワードを使用する必要がありますか?

すべてのクラスがヒープ上で動的に割り当てられ、実際にはほとんどの操作でポインターを使用するため、C# でrefandoutキーワードをどこで使用するかについて、やや戸惑っています。 もちろん、キーワードはプリミティブと構造体にとって意味があります。
outref

また、リストを直接送信するのではなく、リストを含むクラスを送信するとどうなりますか? (internal必要です)、まだ使用する必要がありますrefか?または関数間で渡す場合、例:

void A(ref LinkedList<int> list){
    B(list);
}

void B(ref LinkedList<int> list){
    _myList = list;
}
4

7 に答える 7

30

refこれは、 C#でのキーワードの使用に関する一般的な誤解です。その目的は、参照によって値または参照型のいずれかを渡すことであり、引数のコピーではなく、実際の引数への直接参照が必要な特定の状況でのみ必要です (値または参照自体)。 . どのような場合でも、参照型参照渡しを混同しないことが不可欠です。

Jon Skeet は、C# でのパラメーターの受け渡しに関する優れた記事を書いています。この記事では、値の型、参照型、値による受け渡し、参照による受け渡し ( ref)、および出力パラメーター ( out) を比較対照しています。時間をかけてこれをすべて読むことをお勧めします。そうすれば、理解がより明確になるはずです。

そのページから最も重要な部分を引用するには:

値のパラメーター:

デフォルトでは、パラメーターは値パラメーターです。これは、関数メンバー宣言で変数用に新しい格納場所が作成され、関数メンバー呼び出しで指定した値から始まることを意味します。その値を変更しても、呼び出しに含まれる変数は変更されません

参照パラメータ:

参照パラメーターは、関数メンバーの呼び出しで使用される変数の値を渡しません。変数自体を使用します。関数メンバー宣言で変数の新しい格納場所を作成するのではなく、同じ格納場所が使用されるため、関数メンバーの変数の値と参照パラメーターの値は常に同じになります。参照パラメーターには、宣言と呼び出しの両方の一部として ref 修飾子が必要です。つまり、何かを参照渡しするときは常に明確です。パラメータを参照パラメータに変更しただけの前の例を見てみましょう。

結論として、私の返信と Jon Skeet の記事を読んで、質問のコンテキストでキーワードを使用する必要がまったくないことがわかると思います。ref

于 2009-06-09T16:39:34.733 に答える
19

あなたがしていることのために、refを使う必要はありません。ref を使用してリストを渡した場合、リストの内容を変更するだけでなく、参照しているリストを呼び出し元が変更できるようになります。

于 2009-06-09T16:41:58.320 に答える
15

参照型で ref を使用する必要があるのは、関数内で新しいオブジェクトを作成する場合だけです。

例 #1 :refキーワードは必要ありません。

// ...
   List myList = new List();
   PopulateList(myList);
// ...
void PopulateList(List AList)
{
   AList.Add("Hello");
   AList.Add("World");
}

例 #2 :refキーワードが必要です。

// ...
   List myList;
   PopulateList(ref myList);
// ...
void PopulateList(ref List AList)
{
   AList = new List();
   AList.Add("Hello");
   AList.Add("World");
}
于 2009-06-09T16:55:23.793 に答える
2

いいえ、ref を使用する必要はありません。

LinkedList はオブジェクトなので、すでに参照型です。パラメータlistは、LinkedList オブジェクトへの参照です。

値の型の説明については、このMSDN の記事を参照してください。値の型は、通常、refまたはoutキーワードを使用するパラメータです。

で参照型を渡すこともできますref。これにより、別のオブジェクトへの参照を指すことができます。

を渡すときはいつでも、object o実際にはオブジェクトへの参照を渡しています。`ref object o' を渡すと、参照への参照が渡されます。これにより、参照を変更できます。

参照型パラメーターを渡すことも理解に役立つ場合があります。

于 2009-06-09T16:36:22.210 に答える
2

投稿した 2 つのスニペットでは、ref でリストを渡す必要はありません。Jon Skeet の言葉を引用すると、オブジェクト参照は値によって渡されます。つまり、メソッドがオブジェクト参照を変更する、または変更する可能性があり、この新しい参照を呼び出し元のメソッドに戻す場合は、参照型を参照する必要があります。例えば:

void methodA(string test)
{
    test = "Hello World";
}

void methodB(ref string test)
{
    test = "Hello World";
}

void Runner()
{
    string first= "string";
    methodA(first);
    string second= "string";
    methodB(ref second);
    Console.WriteLine((first == second).ToString()); //this would print false
}
于 2009-06-09T16:47:46.923 に答える
2

私のように C++ に慣れているプログラマーのために、この回答を追加します。

クラス、インターフェイス、デリゲート、および配列はreference typesです。これは、基になるポインターがあることを意味します。通常の関数呼び出しは、このポインター (参照) を値でコピーしますが、参照による送信では、この参照への参照が送信されます。

//C# code:
void Foo(ClassA     input)
void Bar(ClassA ref input)

//equivalent C++ code:
void Foo(ClassA*  input)
void Bar(ClassA*& input)

int、double などの構造体や文字列 (文字列はこれらの例外ですが、同様に機能します) などのプリミティブはヒープに割り当てられるため、動作が少し異なります。

//C# code:
void Foo(StructA     input)
void Bar(StructA ref input)

//equivalent C++ code:
void Foo(StructA  input)
void Bar(StructA& input)

キーワードは、メソッドの宣言と呼び出しの両方で使用するref必要があるため、参照されていることは明らかです。

//C# code:
void Foobar(ClassB ref input)
...
ClassB instance = new ClassB();
Foobar(ref instance);

//equivalent C++ code:
void Foobar(ClassB*& input)
...
ClassB instance* = new ClassB();
Foobar(instance);

前にも言ったように、この詳細な説明を読んでください。文字列についても説明します。



興味深いことに、参照による呼び出しは基になるポインターで機能するため、次のコードにたどり着きます。

//C# code:
void Foo(ClassA input){
    input = input + 3;
}
void Bar(ClassA ref input){
    input = input + 3;
}
//equivalent C++ code:
void Foo(ClassA&  input){
    input = input + 3;
}
void Bar(ClassA*&  input){
    *input = *input + 3;
}
//equivalent pure C code:
void Fun(ClassA* input){
    *input = *input + 3;
}
void Fun(ClassA** input){
    *(*input) = *(*input) + 3;
}

これは大まかに同等ですが、ある程度は正しいです。

于 2009-06-09T21:26:29.650 に答える