C#是通过引用还是作为副本将List <t>传递给方法?</t>

时间:2014-05-06 09:27:17

标签: c# pass-by-reference pass-by-value

从C / C ++迈出C#世界的第一步,所以细节有点模糊。据我所知,类默认通过引用传递,但是例如。列表与LT;串GT;喜欢在:

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 本身而非副本?

7 个答案:

答案 0 :(得分:13)

它通过引用传递。 List<T>是一个类,所有类实例都通过引用传递。

答案 1 :(得分:9)

行为始终如一:通过复制传递。如果参数是一个对象,则复制对象的引用,因此实际上您正在处理相同的对象/列表/无论如何。

答案 2 :(得分:4)

基础的东西总是:值类型按值传递,引用类型“通过引用传递”(引用因为引用的值实际上是通过值传递的,但大多数人为了简洁起见忽略了它)

ref关键字与引用进行协调的最简单方法是:引用类型的引用按值传递。在标准情况下,这会简单地将引用传递给列表(而不是整个列表)到该方法。

ref关键字在引用类型上使用时,会在语义上传递对引用的引用(我真的很难不说“指向指针”)。

如果您的方法是将ref参数重新分配给新对象,则调用者也会看到此新分配。如果没有ref关键字,该方法只需重新分配自己的参考值本地副本,而调用者仍然可以引用其原始对象。

以上解释是从Jon Skeet's article on the topic

无耻地进行的
  

这种差异对于理解参数绝对至关重要   传递C#,这就是为什么我认为这样说非常混乱   默认情况下,对象通过引用传递而不是正确的   声明对象引用默认按值传递。

只有在您打算重新分配参数并使其对调用者可见时,才需要ref关键字。在大多数情况下,您会发现不需要它。您可以重新编写DoStuff以删除它,并仍然按值成功传递对列表的引用:

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

答案 3 :(得分: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 :(得分:2)

如果要修改原始列表,方法中的ref关键字是多余的:List<T>是C#中的引用类型(class),因此将传递给方法引用;因此该方法将操纵原始列表。

传递Value Type时,它会创建值本身的副本。 传递Reference Type时,它将创建引用的副本。

详细了解C#中的Value and Reference Types

答案 5 :(得分:2)

列表以引用方式传递。这意味着实际上方法中的strs变量引用与方法外的sl变量相同的列表。 如果你使用ref,你实际上可以在方法中重新分配sl变量。

strs = new List<string>()

会使sl指向新列表。

由于您来自C / C ++:ref可被视为安全指针&#39;。它类似于使用&amp; strs

答案 6 :(得分:-1)

它的参考。没有必要包括“ref”。

最好的问候。