C# 是通过引用还是作为副本将 List<T> 传递给方法? [复制]
Posted
技术标签:
【中文标题】C# 是通过引用还是作为副本将 List<T> 传递给方法? [复制]【英文标题】:Does C# pass a List<T> to a method by reference or as a copy? [duplicate] 【发布时间】:2014-06-22 20:04:58 【问题描述】:从 C/C++ 开始我在 C# 世界中的第一步,所以细节有点模糊。据我了解,默认情况下,类是通过引用传递的,但是例如。列表
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)
【问题讨论】:
class
通过引用传递。 struct
按值传递。
this 文章应该可以帮助您更好地了解这个领域。
似乎 C# 和 C++ 中的“按引用传递”来自不同的字典。无论如何,谢谢大家的回答——模糊的细节现在不那么模糊了。
@Scre 有些人在 C# 中以不同的含义混淆使用“按引用传递”,因为术语“引用”和“引用类型”(实际上是指“引用”的不同含义)。但是在 C# 中正确使用“按引用传递”,ref
参数,几乎与一般 C++ 和 CS 中称为按引用传递的东西相同。
【参考方案1】:
如果要修改原始列表,方法中的ref
关键字是多余的:List<T>
是引用类型(C# 中的class
),因此将通过引用传递给方法;因此该方法将操纵原始列表。
当传递Value Type
时,它将创建值本身的副本。
当传递Reference Type
时,它将创建引用的副本。
详细了解 C# 中的 Value and Reference Types。
【讨论】:
ref
不是多余的。有了它,strs = ...;
会影响调用者。没有它,它就不会。
另外,将引用类型对象发送到没有ref
关键字的方法会导致创建引用的新副本。 “冗余”意味着它是相同的。事实并非如此。【参考方案2】:
它是通过引用传递的。 List<T>
是一个类,所有的类实例都是通过引用传递的。
【讨论】:
【参考方案3】:行为总是相同的:通过复制传递。如果参数是对象,则复制对象的引用,因此实际上您正在处理相同的对象/列表/任何内容。
【讨论】:
【参考方案4】:底层的东西总是:值类型是按值传递的,而引用类型是“按引用传递的”(引用是因为引用的值实际上是按值传递的,但为了简洁起见,大多数人忽略了这一点) .
协调ref
关键字与引用的最简单方法是:引用类型的引用按值传递。在标准情况下,这具有简单地将对列表(而不是整个列表)的引用传递给方法的效果。
ref
关键字,当用于引用类型时,在语义上传递对引用的引用(我真的很难不说“指向指针的指针”)。
如果您的方法将ref
参数重新分配给一个新对象,调用者也会看到这个新分配。而如果没有 ref
关键字,该方法将简单地重新分配他们自己的引用值的本地副本,并且调用者仍然会引用其原始对象。
以上解释无耻取自Jon Skeet's article on the topic:
这种差异对于理解参数绝对至关重要 传入 C#,这就是为什么我认为这样说非常令人困惑的原因 默认情况下,对象是通过引用而不是正确的 声明对象引用默认按值传递。
ref
关键字仅在您打算重新分配参数并使其对调用者可见时才需要。在大多数情况下,您会发现它是不需要的。您的 DoStuff
可以重写以将其删除,并且仍然可以成功地按值传递对列表的引用:
void DoSomething(List<string> strs)
strs.Add("Hello");
【讨论】:
这是我对它如何工作的第一个“预感”,但不太确定。 @scre 我强烈推荐阅读 Jon Skeet 的那篇文章,并拿起他的 C# in Depth 书,他有很好的技巧来组织抽象或复杂主题的解释,以便于阅读。跨度> 【参考方案5】:它的参考。不必包含“ref”。
最好的问候。
【讨论】:
ref
不是多余的。有了它,strs = ...;
会影响调用者。没有它,它就不会。
(参考值不需要)【参考方案6】:
列表通过引用传递。这实际上意味着方法内部的 strs 变量引用了与方法外部的 sl 变量相同的列表。 如果你会使用 ref,你实际上可以在方法中重新分配 sl 变量。
strs = new List<string>()
将使 sl 指向新列表。
由于您来自 C/C++: ref 可以被视为“安全指针”。类似于使用 &strs
【讨论】:
【参考方案7】:除了其他答案之外,了解 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
【讨论】:
以上是关于C# 是通过引用还是作为副本将 List<T> 传递给方法? [复制]的主要内容,如果未能解决你的问题,请参考以下文章
为啥 C# 数组对 Enumeration 使用引用类型,而 List<T> 使用可变结构?