通过副本或参考传递?

Posted

技术标签:

【中文标题】通过副本或参考传递?【英文标题】:Pass by copy or reference? 【发布时间】:2011-04-03 01:24:02 【问题描述】:

我对 C# 有点陌生,只是想知道是否有一个默认作为副本传递的类列表(常用)。如何识别它们?

我知道基本的基本对象类型——int、uint、float、strings……——是通过复制传递的。

【问题讨论】:

Thomas Levesque 的回答回答了这个问题。需要注意的是,当值类型被复制时,默认情况下它只是一个浅拷贝——如果一个结构包含一个引用类型,则该副本将指向同一个引用对象,而不是克隆一个新对象。 【参考方案1】:

在 C# / .Net 中,对象可以分为值类型或引用类型 [1]。值类型是派生自System.ValueType 并在C# 中使用struct 类型声明定义的任何类型。这些是通过副本/值传递的。

引用类型不是从System.ValueType 派生的类型,而是在C# 中使用class 关键字定义的。引用类型实例的标识符称为引用(类似于指针)。默认情况下,这些也是按值传递的,但仅传递引用而不传递整个对象。

您的问题还提到 string 实例是通过副本传递的。 .Net 中的String 是一个引用类型(直接派生自System.Object),因此不通过完整副本传递。

[1] 指针在这里可能值得他们自己的类,但我在本次讨论中忽略了它们。

【讨论】:

谢谢,System.ValueType 之间的继承帮助我理解了这一点!【参考方案2】:

默认情况下,所有类型都按值传递。 值类型 (struct) 和引用类型 (class) 之间的区别在于,对于值类型,值的副本是传递给方法,而对于引用类型,只传递一个引用。

See MSDN 了解更多详情。

另外,不要混淆值/引用类型的概念,以及按值或按引用传递参数的概念。详情请参阅 Jon Skeet 的 this article

【讨论】:

不,两者都是按值传递的。在引用的情况下,虽然它是按值传递的引用,而不是对象。 确实,措辞很糟糕……我修好了【参考方案3】:

一般来说,

值类型,其中包括本机类型(intfloat、...)以及 structs 是“按副本”传递的(如您所说它),而在

引用类型,其中包括classes,只复制一个引用而不是完整的对象。

但请注意,string 不是“通过复制”传递的!这是一个引用类型,但由于它是不可变的,it behaves similar to a value type。

请注意,ref 关键字在两种情况下都很有用:对于值类型,这意味着将值复制回来。在引用类型的情况下,这意味着 reference 可以更改(即,您可以将变量分配给新对象,而不仅仅是更改对象的属性。)

【讨论】:

-1 所有类型在 c# 中都是按值传递的,除非您使用 ref 或 out 关键字。碰巧的是,对于引用类型,值就是引用。例如如果您将引用类型传递给方法并在方法中将其设置为 null,如果不将您传递的变量清空,则仅在方法中传递 COPY。 @Ben:没错,这就是为什么我在第二种情况下避免使用“通过引用”这个短语,并明确提到了 ref 关键字的使用。我已经改写了我的答案以使这一点更清楚。 删除了我的 -1 因为你更新了你的答案更清楚了。 @Ben:谢谢(删除 -1 以及反馈)。【参考方案4】:

还要注意结构对象可以包含引用类型:

struct Currency

    int Amount get;set; // is referenced by value (copy)
    string Code get;set; // is referenced by reference

当您像这样使用该结构时:

var obj1 = new CurrencyAmount = 1, Code = "USD";
var obj2 = obj1;

然后

object.ReferenceEquals(obj1.Code, obj2.Code); // false - string is reference type, but used inside value type

如果您已将 Currency 声明为类,则对 Code 的引用是相同的。

【讨论】:

以上是关于通过副本或参考传递?的主要内容,如果未能解决你的问题,请参考以下文章

传递常量引用与创建临时常量副本相同,那么为啥要传递常量引用呢? [复制]

const int& 是不是传递了引用或副本

我可以使用副本集名称通过 mongo-connector 进行连接吗

通过作为方法参数传递对象的副本

通过 '*this' 传递副本时的奇怪行为

C# 是通过引用还是作为副本将 List<T> 传递给方法? [复制]