c#传递List通过引用或作为副本的方法
本文关键字:副本 方法 引用 List 传递 | 更新日期: 2023-09-27 18:01:48
从C/c++开始我在c#世界的第一步,所以细节有点模糊。类,据我所知,默认情况下是通过引用传递的,但是eg呢?List
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实际上作用于sl本身而不是副本?Strs)
通过引用传递。List<T>
是一个类,所有的类实例都是通过引用传递的
行为总是相同的:通过复制传递。如果形参是一个对象,则复制对该对象的引用,因此实际上您正在处理相同的对象/列表/等等。
除了其他答案之外,理解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
基本的事情总是:值类型是按值传递的,引用类型是"按引用传递的"(引号是因为引用的值实际上是按值传递的,但大多数人为了简洁而忽略了这一点)。
调和ref
关键字与引用的最简单方法是:引用类型的引用按值传递。在标准情况下,这样做的效果是简单地将对列表的引用(而不是整个列表)传递给方法。
ref
关键字,当在引用类型上使用时,在语义上传递一个引用到引用(我真的很难不说"指针指向指针")。
如果您的方法要将ref
参数重新赋值给一个新对象,调用者也会看到这个新的赋值。然而,如果没有ref
关键字,该方法将简单地重新分配引用值的本地副本,而调用者仍将拥有对其原始对象的引用。
以上解释无耻地摘自Jon Skeet关于这个话题的文章:
这个区别对于理解parameter是至关重要的在c#中传递,这就是为什么我认为这样说非常令人困惑的原因对象默认通过引用传递,而不是正确的默认情况下按值传递对象引用的语句。
ref
关键字仅在您打算重新分配实参并使其对调用者可见时才需要。在大多数情况下,你会发现它是不需要的。您的DoStuff
可以重写以删除它,并且仍然成功地通过值传递对列表的引用:
void DoSomething(List<string> strs)
{
strs.Add("Hello");
}
如果你想修改原始列表,方法中的ref
关键字是多余的:List<T>
是一个引用类型(c#中的class
),因此将通过引用传递给方法;因此,该方法将操作原始列表。
当传递Value Type
时,它将创建值本身的副本。当传递一个Reference Type
时,它将创建一个引用的副本。
列表通过引用传递。这实际上意味着方法内部的strs变量与方法外部的sl变量引用相同的列表。如果你想使用ref,你可以在方法中重新赋值sl变量。
strs = new List<string>()
将使sl指向新的列表。
因为你来自C/c++: ref可以被认为是一个"安全指针"。它类似于使用&strs
参考。不需要包含ref
问好。