C# 回顾:ref 知多少
要理解C# 7的ref
特性,需要认真回顾C# 6以前版本中ref
参数的工作原理,首先是变量和值之间的区别。
对于变量这个概念的理解因人而异。可以把变量想象成一张纸,如图13-1所示。这张纸上共有3项信息:
- 变量的名称;
- 编译时类型;
- 当前值。
图13-1 把变量想象成一张纸 |
给变量赋新值,就相当于擦掉当前值然后写上一个新值。当变量类型是引用类型时,纸上所写的值就不再是对象本身,而是对象的引用。对象的引用,就是通过地址找到对象,就像通过街道地址找到某个建筑一样。如果两张纸上写着相同的地址,那么这两个地址指向同一个建筑;两个引用值相同的变量,指向的是同一个对象。
提示
ref
关键字和对象引用是不同的概念。虽然二者有相似性,但需要加以区分。通过值传递对象引用和通过引用传递变量是不同的。下面过使用对象引用而不是引用来重点区分这两个概念。
当把某个变量值复制给另外一个变量时,只是这个值本身发生了复制。这两张纸依然是独立的两张纸,之后任何一个变量的值改变都不会影响另外一个变量,见图13-2。
图13-2 把值赋给一个新变量 |
这种方式的值复制,和调用方法时对值参数的操作是相同的:方法实参的值被复制到了另一张新纸上——形参中,如图13-3所示。实参可以是变量,也可以是任何适当类型的表达式。
图13-3 使用值参数调用方法:方法形参是新变量,其初始值是实参的值 |
但ref
参数的行为与此不同,见图13-4。使用ref
参数,不会创建一张新纸,而是由调用方提供一张现有的、包含初始值的纸。可以将其看作一张纸上写着两个名字:一个是调用方使用的该变量的标识,另一个是形参名称。
图13-4 ref参数使用同一张纸,而不是创建一张新纸并复制值 |
如果在方法中修改了ref
参数的值,即修改了纸上的现有值。当方法返回时,修改的结果就会反应给调用方,因为修改的是同一张纸上的值。
说明 看待形参和变量的方式有多种。某些作者提出了不同的理解方式:把
ref
参数看作完全独立的变量,它有一个自动的中间层,任何关于ref
参数的访问都会先访问中间层。这种解释更接近IL的工作原理,但对我来说帮助不大。
此外,并不是每个ref
参数都会使用不同的纸。下面这个例子有些极端,但有助于我们理解ref
参数,以及接下来要讲的ref
局部变量。
代码清单13-1 多个
ref
参数使用同一个变量
static void Main()
{
int x = 5;
IncrementAndDouble(ref x, ref x);
Console.WriteLine(x);
}
static void IncrementAndDouble(ref int p1, ref int p2)
{
p1++;
p2 *= 2;
}
这段代码的执行结果是12,x
、p1
、p2
表示的是同一张纸。这张纸上的初始值是5,p1++
把它变成6,然后p2 *= 2
把6翻倍变成12。图13-5展示了上述过程。
图13-5 两个ref参数指向同一张纸 |
一种常见的做法是把它们看作别名:变量x
、p1
和p2
都是同一个存储位置的别名,它们只是通往同一块内存的不同方式而已。
上述内容可能略显陈旧、烦琐,但这是在为接下来C# 7真正的新特性做知识铺垫。以纸张作为思维模型来理解变量,便于学习新特性。
(完)
相关阅读:
C# 回顾:ref 知多少
C# ref 局部变量和 ref return
in 参数(C# 7.2)
将结构体声明为只读(C# 7.2)
使用 ref 参数或者in参数的扩展方法(C# 7.2)
类 ref 结构体(C# 7.2)
评论
发表评论