Reputation: 2118
Maybe an old question, but am not finding anything comprehensive on the internet.
If the default parameter passing method in C# is By value, then how does it affect the initial Reference Type variable?
I.e. in the below example, why will it print "Hello World" instead of just "Hello", if it was parameter passing by value?
void Foo (StringBuilder x)
{
x.Append (" World");
}
StringBuilder y = new StringBuilder();
y.Append ("Hello");
Foo (y);
Console.WriteLine (y);
Upvotes: 1
Views: 7323
Reputation: 19407
First, understand that in C# there are two fundamental types: Value Types and Reference Types.
Furthermore, each of those types can be passed to a method By Value or By Reference. (So, that means there are actually four ways to pass a parameter to a method.)
And regardless of how you pass a Reference Type (By Value or by Reference), you have the ability to change the value to which that reference points!
Now, with regard to your particular example, your parameter of question is of type StringBuilder
which is a Reference Type. (StringBuilder
is a Class and Classes are Reference Types.) And again, because you are passing a Reference Type to your method, you are able to change the value associated with that reference inside of that method.
Finally, note that you are passing your Reference Type parameter By Value. If instead you were to pass your Reference Type By Reference and then set it to null
, you would actually destroy the value associated with the reference. (That would be the same as setting the parameter variable to null
outside of the method.)
You can find a more more thorough and very readable explanation here: C# Concepts: Value vs Reference Types
Upvotes: 4
Reputation: 4594
Compare the following. First with StringBuilder (reference type):
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
}
Here the struct is copied, as is the reference to the StringBuilder along with it, but the StringBuilder itself is not copied.
And now with a mutable struct (value type):
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)
}
In this case everything copied. However if we change this into a reference type:
public class Tmd
{
public EvilMutable em;
}
Then, we'll get this:
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)
Upvotes: 1
Reputation: 22555
Because StringBuilder is a mutable
class and will passed by reference. Instead of string builder you use string it will be Hello
because string is immutable
. Also for value types like int
, enum
, ... there isn't any change.
For simplicity, Value types are struct, enum, primitive types, ... and reference types are classes, but As I mentioned there are some classes like string which are immutable and in fact, they will be passed by value.
Upvotes: 3
Reputation: 94645
That parameter is still a pass-by-value but parameter variable x
has a reference of the StringBuilder
object.
The reference variable y has the reference of StringBuilder object
StringBuilder y = new StringBuilder();
and reference of StringBuilder object is copied to parameter x of Foo.
Foo (y);
Upvotes: 3
Reputation: 5566
StringBuilder is a class, so it will be passed by reference.
read more: Value vs reference types
Upvotes: 1
Reputation: 34780
Anything other than the primitive types (such as int
, byte
etc) are passed by reference by default. You are passing the same StringBuilder
instance to the method.
Upvotes: 2