C#中的默认参数传递
Posted
技术标签:
【中文标题】C#中的默认参数传递【英文标题】:Default parameter passing in C# 【发布时间】:2011-12-24 08:07:48 【问题描述】:也许是一个老问题,但在互联网上找不到任何全面的东西。
如果C#中默认的参数传递方式是By value,那么它对初始Reference Type变量有什么影响呢?
即在下面的示例中,如果它是按值传递的参数,为什么它会打印“Hello World”而不是“Hello”?
void Foo (StringBuilder x)
x.Append (" World");
StringBuilder y = new StringBuilder();
y.Append ("Hello");
Foo (y);
Console.WriteLine (y);
【问题讨论】:
对字符串生成器对象的引用是按值传递的。 【参考方案1】:首先,了解 C# 中有两种基本类型:值类型和引用类型。
此外,这些类型中的每一种都可以传递给 By Value 或 By Reference 方法。 (因此,这意味着实际上有四种方式将参数传递给方法。)
无论您如何传递引用类型(按值或按引用),您都可以更改该引用指向的值!
现在,关于您的特定示例,您的问题参数是 StringBuilder
类型,它是一个引用类型。 (StringBuilder
是一个 Class 并且 Classes 是引用类型。)同样,因为您将引用类型传递给您的方法,您可以在该方法内部更改与该引用关联的值.
最后,请注意您是按值传递引用类型参数。相反,如果您传递您的引用类型By Reference,然后将其设置为null
,您实际上会破坏与引用关联的值。 (这与将参数变量设置为方法的null
outside 相同。)
您可以在此处找到更全面、更易读的解释:C# Concepts: Value vs Reference Types
【讨论】:
【参考方案2】:该参数仍然是按值传递,但参数变量x
具有StringBuilder
对象的引用。
引用变量y有StringBuilder对象的引用
StringBuilder y = new StringBuilder();
StringBuilder 对象的引用被复制到 Foo 的参数 x 中。
Foo (y);
【讨论】:
【参考方案3】:因为 StringBuilder 是一个mutable
类并且将通过引用传递。你使用字符串而不是字符串生成器,它将是Hello
,因为字符串是immutable
。对于 int
、enum
等值类型,也没有任何变化。
为简单起见,值类型是结构、枚举、原始类型,... 和引用类型都是类,但正如我提到的,有一些类如字符串是不可变的,实际上它们将按值传递。
【讨论】:
太棒了!感谢大家快速而详细的回答。面试时被问到这个问题!我只是在验证我的答案;)所以总结一下:C# 中的默认参数传递方法是什么... 1. 值类型按值传递,引用类型按引用传递(现在我知道它不是 :) ,但我已将其作为答案) 2. 通过值传递不可变类型,通过引用传递可变类型 3. 通过值传递原始类型,通过引用传递非原始类型 4. 还是其他什么? @Vishruth 其实你的回答已经足够好了,而且我认为这不是一个很好的面试问题,如果你能理解值类型和引用类型之间的区别,以及不可变和可变对象之间的区别,那就很好了够了,只是他们面试太多,把它当成纸笔考试。【参考方案4】:除了原始类型(例如int
、byte
等)之外的任何内容都默认通过引用传递。您正在将相同的 StringBuilder
实例传递给该方法。
【讨论】:
它们将通过引用传递,但如果它们是不可变的,则它们没有变化。例如string
不是原始类型,但它的值没有变化。
-1:引用是按值传递的,此外还有DateTime等非原始值类型。
根据 MSDN 自己的文章,字符串是原始的 msdn.microsoft.com/en-us/library/aa711900%28VS.71%29.aspx (当我在 .net 中向 google 键入原始类型时的第一个结果)。我知道字符串实例在内存中是不可变的,但是“对于用户”,它充当原始类型。 (从同样的角度来看,日期时间也是原始的)
@Vishruth 原始类型是数字类型;整数和浮点数。并且像字符串和日期时间这样的类型在.net中也被认为是原始的,从某种意义上说,如果你将它们传递给一个方法,它们的值将被传递,并且你对传递的值所做的任何更改都不会反映到另一个(第一)另一种方法的价值。另一方面,所有其他类型(据我所知)都是引用,当您将它们传递给方法时,它们的“指针”被复制,仍然“指向内存中的同一个对象”
@canpoyrazoğlu 是的,这是我的错误,但我的观点或 Henrik 的观点是,除了你所说的之外,还有其他类型,它们是值类型,实际上我们没有原始类型/非原始类型为了分离它们的调用方式,这些是一般规则的子类,值类型和引用类型,所有结构都是值类型但不是原始的......【参考方案5】:
StringBuilder是一个类,所以会通过引用传递。
阅读更多:Value vs reference types
【讨论】:
【参考方案6】:比较以下。首先使用 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
这里结构被复制,对 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)
【讨论】:
以上是关于C#中的默认参数传递的主要内容,如果未能解决你的问题,请参考以下文章