11

在我深入研究类设计之前,我只想检查一下我对 C# 处理方式的理解。我目前的理解是:

  • Struct是一种类型,这意味着它实际上包含其中定义的数据成员。
  • Class是一种引用类型,这意味着它包含对其中定义的数据成员的引用。

  • 方法签名通过value传递参数,这意味着将 value 的副本传递到方法内部,这对于大型数组和数据结构来说是昂贵的。

  • 使用refout关键字定义参数的方法签名将改为通过引用传递参数,这意味着提供了指向对象的指针。

我不明白的是当我调用一个方法时会发生什么,实际发生了什么。new() 是否被调用?它只是自动复制数据吗?还是它实际上只是指向原始对象?以及使用refout对此有何影响?

4

3 回答 3

13

我不明白的是当我调用一个方法时会发生什么,实际发生了什么。new() 是否被调用?它只是自动复制数据吗?还是它实际上只是指向原始对象?以及使用 ref 和 out 对此有何影响?

简短的回答:

空的构造函数不会被自动调用,它实际上只是指向原始对象。
使用 ref 和 out 不会影响这一点。

长答案:

我认为理解 C# 如何处理将参数传递给函数会更容易。
实际上一切都是按值传递的
真的吗?!一切都按价值计算?
是的!一切!

当然,传递类和简单类型对象(例如 Integer)之间必须存在某种差异,否则,在性能方面将是一个巨大的退步。

事情是这样的,当你将对象的类实例传递给函数时,真正传递给函数的是指向类的指针。当然,指针可以按值传递而不会导致性能问题。

实际上,一切都是按值传递的;只是当您“传递一个对象”时,实际上是在传递对该对象的引用(并且您正在通过值传递该引用)。

一旦我们在函数中,给定参数指针,我们就可以与通过引用传递的对象相关联。
您实际上不需要为此做任何事情,您可以直接与作为参数传递的实例相关联(如前所述,整个过程是在幕后完成的)。

明白了这一点,你大概就明白了,空的构造函数不会被自动调用,它其实只是指向了原来的对象


编辑:

至于outref,它们允许函数更改参数的值,并使该更改在函数范围之外持续存在。
简而言之,对值类型使用 ref 关键字的作用如下:

int i = 42;
foo(ref i);

将在 C++ 中转换为:

int i = 42;    
int* ptrI = &i;
foo(ptrI)

而省略 ref 将简单地转换为:

int i = 42;
foo(i)

将这些关键字用于引用类型对象,将允许您为传递的参数重新分配内存,并使重新分配在函数范围之外持续存在(有关更多详细信息,请参阅MSDN 页面

旁注:
ref 和 out 之间的区别在于 out 确保被调用的函数必须为 out 参数分配一个值,而 ref 没有这个限制,然后您应该通过自己分配一些默认值来处理它,因此, ref 暗示参数的初始值对函数很重要,并可能影响它的行为。

于 2013-06-30T05:05:39.943 回答
5

将值类型变量传递给方法意味着将变量的副本传递给方法。在方法内部对参数进行的任何更改都不会影响存储在变量中的原始数据。

如果你想让被调用的方法改变参数的值,你必须通过引用传递它,使用 ref 或 out 关键字。

当您通过值传递引用类型参数时,可以更改引用指向的数据,例如类成员的值。但是,您不能更改引用本身的值;也就是说,您不能使用相同的引用来为新类分配内存并让它在块之外持续存在。为此,请使用 ref(或 out)关键字传递参数。

参考:传递参数(C#)

于 2013-06-30T04:24:14.597 回答
0

可悲的是,在 C# 或 VB.NET 中无法按值传递对象。我建议您改为传递,例如,New Class1(Object1),其中 Object1 是 Class1 的一个实例。您将不得不编写自己的 New 方法来执行此操作,但至少您对 Class1 具有简单的按值传递功能。

于 2018-02-01T00:43:17.903 回答