web-dev-qa-db-ja.com

C#はList <T>を参照またはコピーとしてメソッドに渡しますか?

C/C++からC#の世界で私の最初の一歩を踏み出しました。私が理解している限りでは、クラスはデフォルトで参照渡しされますが、例えば次のようなリスト<string>:

void DoStuff(List<string> strs)
{
    //do stuff with the list of strings
}

その他

List<string> sl = new List<string>();
//next fill list in a loop etc. and then do stuff with it:
DoStuff(sl);

は sl この場合、参照によって渡されるか、コピーが作成されるため、次のようにワーカー関数を再定義する必要があります

void DoStuff(ref List <string> strs)
sl
16
Scre

参照渡しです。 List<T>はクラスであり、すべてのクラスインスタンスは参照によって渡されます。

14

動作は常に同じです:コピーによる受け渡し。パラメータがオブジェクトの場合、オブジェクトへのreferenceがコピーされるため、実際には同じオブジェクト/リスト/その他で作業しています。

9

基礎となることは常に次のとおりです。値型は値で渡され、参照型は「参照で渡されます」(引用の値は実際に値で渡されるため引用されますが、ほとんどの人は簡潔にするためにそれを無視します)。

参照に対してrefキーワードを調整する最も簡単な方法は、参照タイプが参照を値で渡すことです。これは、標準の場合、リストへの参照(リスト全体ではなく)をメソッドに渡すだけの効果があります。

refキーワードは、参照型で使用されると、参照を意味的に参照に渡します(「ポインターへのポインター」と言わないように本当に苦労します)。

メソッドがref引数を新しいオブジェクトに再割り当てする場合、呼び出し元にもこの新しい割り当てが表示されます。 refキーワードがない場合、メソッドは単に参照値のローカルコピーを再割り当てし、呼び出し元は元のオブジェクトへの参照を保持します。

上記の説明は、恥知らずに トピックに関するジョンスキートの記事 から引用されています。

この違いは、C#でのパラメーターの受け渡しを理解するために絶対に不可欠であり、オブジェクト参照がデフォルトで値で渡されるという正しいステートメントではなく、オブジェクトがデフォルトで参照で渡されると言うのは非常に混乱していると思う理由です。

refキーワードが必要なのは、引数を再割り当てして、呼び出し元に表示させる場合のみです。ほとんどの場合、それは必要ないことがわかります。 DoStuffを書き換えて削除しても、値によるリストへの参照を正常に渡すことができます。

void DoSomething(List<string> strs) 
{ 
    strs.Add("Hello");
}
4

他の回答に加えて、refの動作を理解することは非常に重要です

デモ用のサンプルコードを次に示します。

static void Main(string[] args)
    {

        List<string> lstStr = new List<string>();

        lstStr.Add("First");
        lstStr.Add("Second");

        Alter(lstStr);

        //Alter(ref lstStr);

        Console.WriteLine("---From Main---");
        foreach (string s in lstStr)
        {
            Console.WriteLine(s);
        }

        Alter2(ref lstStr);

        Console.WriteLine("---From Main after passed by ref---");
        foreach (string s in lstStr)
        {
            Console.WriteLine(s);
        }

        Console.ReadKey();
    }

    static void Alter(List<string> lstStr2)
    {
        lstStr2.Add("Third");

        Console.WriteLine("----From Alter----");
        foreach (string s in lstStr2)
        {
            Console.WriteLine(s);
        }

        lstStr2 = new List<string>();
        lstStr2.Add("Something new");

        Console.WriteLine("----From Alter - after the local var is assigned somthing else----");

        foreach (string s in lstStr2)
        {
            Console.WriteLine(s);
        }

    }

    static void Alter2(ref List<string> lstStr2)
    {
        lstStr2 = new List<string>();
        lstStr2.Add("Something new from alter 2");

        Console.WriteLine("----From Alter2 - after the local var is assigned new list----");

        foreach (string s in lstStr2)
        {
            Console.WriteLine(s);
        }

    }


//----From Alter----
//First
//Second
//Third
//----From Alter - after the local var is assigned somthing else----
// Something new
// ---From Main---
// First
// Second
// Third
// ----From Alter2 - after the local var is assigned new list----
// Something new from alter 2
// ---From Main after passed by ref---
// Something new from alter 2
4
ZedBee

元のリストを変更する場合、メソッドのrefキーワードは冗長です。 List<T> は参照型(C#ではclass)です。参照によりメソッドに渡されます。したがって、メソッドは元のリストを操作します。

Value Typeを渡すと、値自体のコピーが作成されます。 Reference Typeを渡すと、参照のコピーが作成されます。

C#の Value and Reference Types の詳細をご覧ください。

2
Yuval Itzchakov

リストは参照で渡されます。つまり、メソッド内のstrs変数は、メソッド外のsl変数と同じリストを参照するということです。 refを使用する場合、メソッド内でsl変数を実際に再割り当てできます。

strs = new List<string>()

slは新しいリストを指すようになります。

C/C++から来ているので、refは「安全なポインター」と見なすことができます。 &strsを使用することに似ています

2
Dennis_E