我正在阅读John Skeet的书"C# in Depth"
。他在第74页上说,每个人都认为参数通过引用传递给函数,同时它通过值传递,并且作为示例他显示了必须在调用代码中证明StringBuilder的代码没有改变。同时在我们的函数StringBuilder实例中更改。
private static void SayHello(StringBuilder s)
{
s.AppendLine("Hello");
}
但是我的实验表明StringBuilder对象发生了变化 - 我们将在控制台中看到“Hello”。这有什么不对?或者我对这个例子的理解有什么问题?
private static void Main(string[] args)
{
var s = new StringBuilder();
Console.WriteLine(s.ToString());
SayHello(s);
Console.WriteLine(s.ToString());
Console.ReadLine();
}
private static void SayHello(StringBuilder s)
{
s.AppendLine("Hello");
}
答案 0 :(得分:4)
阅读页面后,他说的是这个。
现在请记住,引用类型变量的值是 引用,而不是对象本身。你可以改变的内容 参数引用的对象,不带参数本身 通过引用传递。
public static void Main()
{
var s = new StringBuilder();
Console.WriteLine(s.ToString());
SayHello(s);
Console.WriteLine(s.ToString());
Console.ReadLine();
}
private static void SayHello(StringBuilder s)
{
s.AppendLine("Hello");
s = null;
}
//output will be Hello
调用此方法时,参数值(对a的引用) StringBuilder)按值传递。如果我要改变的价值 方法中的构建器变量 - 例如,使用语句 builder = null;相反,调用者不会看到更改 到了神话。
所以他解释说你不能破坏SayHello中的对象StringBuilder
,你可以只改变这个对象的内容。我也不知道。
编辑:关于您的评论
当你在SayHello中传递s
时,你正在创建新的引用,Main
方法和SayHello
中的引用都引用同一个对象。但它们就像2个不同的参考文献一样存在。
如果你写的话
private static void SayHello(StringBuilder s)
{
s.AppendLine("Hello");
s = new StringBuilder();
}
SayHello
中s的引用将指向另一个对象,但这不会更改Main方法中的任何内容,因为引用指向您编写Hello的上一个对象。所以输出再次是Hello。
如果您想传递确切参考,请使用ref
所以,如果你写
private static void SayHello(ref StringBuilder s)
{
s.AppendLine("Hello");
s = null;
//you will receive an exception in Main method, because now the value in the reference is null.
}
答案 1 :(得分:1)
考虑以下类比:
new StringBuilder()
)并获得了一张授予您访问权限的密钥(s
)。s.AppendLine
)并且给了他一把钥匙的副本,这样他就可以进入你的公寓并进行清理。基本上当你按值传递引用类型时会发生什么。
现在考虑以下事项:
new StringBuilder()
)并获得了一张授予您访问权限的密钥(s
)。s.AppendLine
)并且给了他你的钥匙,以便他可以清理你的公寓。这是通过引用传递引用类型时会发生什么。