也许是一个老问题,但我没有在互联网上找到任何全面的内容。
如果C#中的默认参数传递方法是By值(根据this),那么它如何影响初始的Reference Type变量。
即。在下面的例子中,为什么它会打印“Hello World”而不是Just“Hello”,如果它是参数传递值?
void Foo (StringBuilder x)
{
x.Append (" World");
}
StringBuilder y = new StringBuilder();
y.Append ("Hello");
Foo (y);
Console.WriteLine (y);
答案 0 :(得分:3)
因为StringBuilder是mutable
类,将通过引用传递。您使用字符串而不是字符串构建器,它将是Hello
,因为字符串是immutable
。对于int
,enum
等值类型,也没有任何变化。
为简单起见,Value类型是struct,enum,primitive类型,...... 和引用类型是类,但正如我所提到的,有一些像string这样的类是不可变的,事实上,它们将通过值传递。
答案 1 :(得分:3)
该参数仍然是值传递,但参数变量x
具有StringBuilder
对象的引用。
引用变量y具有StringBuilder对象的引用
StringBuilder y = new StringBuilder();
并将StringBuilder对象的引用复制到Foo的参数x。
Foo (y);
答案 2 :(得分:3)
首先,要了解在 C#中有两种基本类型:值类型和引用类型。
此外,每种类型都可以传递给方法按价值或按参考。 (所以,这意味着实际上有四种方式将参数传递给方法。)
无论您如何传递参考类型(按值或按参考),您都可以更改参考点所指向的值!
现在,关于您的特定示例,您的问题参数的类型为StringBuilder
,它是参考类型。 (StringBuilder
是一个类,类是引用类型。)同样,因为您将一个引用类型传递给您的方法,您可以更改与该引用相关的值。那种方法。
最后,请注意您正在传递“参考类型”参数“按值”。如果您要传递参考类型按参考,然后将其设置为null
,则实际上会销毁与参考相关联的值。 (这与将参数变量设置为方法外的<{1}} 相同。)
您可以在此处找到更全面,更易读的解释:C# Concepts: Value vs Reference Types
答案 3 :(得分:2)
默认情况下,通过引用传递除基本类型之外的任何内容(例如int
,byte
等)。您正在将相同的StringBuilder
实例传递给方法。
答案 4 :(得分:1)
StringBuilder 是一个类,因此它将通过引用传递。
答案 5 :(得分:1)
比较以下内容。首先使用StringBuilder(引用类型):
public struct Tmd
{
public StringBuilder sb;
}
public void DoIt(Tmd a)
{
a.sb.Append(" World!");
}
public void Main()
{
Tmd a = new Tmd();
a.sb = new StringBuilder();
a.sb.Append("Hello");
DoIt(a);
Console.WriteLine(a.sb); // Hello World
}
这里复制了struct,对StringBuilder的引用也是如此,但是不会复制StringBuilder本身。
现在使用可变结构(值类型):
public struct EvilMutable
{
public int i;
}
public struct Tmd
{
public EvilMutable em;
}
public void DoIt(Tmd a)
{
a.em.i += 1;
}
public void DoIt(EvilMutable em)
{
em.i += 1;
}
public void Main()
{
Tmd a = new Tmd();
a.em.i += 5;
Console.WriteLine(a.em.i); // 5
DoIt(a);
Console.WriteLine(a.em.i); // 5 (unchanged)
DoIt(a.em);
Console.WriteLine(a.em.i); // 5 (unchanged)
}
在这种情况下,一切都被复制了。但是,如果我们将其更改为引用类型:
public class Tmd
{
public EvilMutable em;
}
然后,我们会得到这个:
Tmd a = new Tmd();
a.em.i += 5;
Console.WriteLine(a.em.i); // 5
DoIt(a);
Console.WriteLine(a.em.i); // 6
DoIt(a.em);
Console.WriteLine(a.em.i); // 6 (unchanged)