Passing variable by Ref. or Value Dilemma - c#

I have some void methods which are static.
Is it better to pass variables by reference or by value, because I'm passing large amount of text into these variables :
public static void renderText(ref StringBuilder build)
{
//Do your job.
}
So could someone explain me, what happens when I send a reference of StringBuilder, does it only access this StringBuilder? (It does not copy it right!).
And just in case I'm not changing the value or any other property of input arguments into methods.
So, in this cases where variables are huge enough and not manipulated, should I always send the reference of it, and if yes does it interfere with something?

Take a look at the following article by Jon Skeet in which he thoroughly explains the difference between passing by reference or by value.
Parameter passing in C#
or this blog post which illustrates the former article:
http://rapidapplicationdevelopment.blogspot.com/2007/01/parameter-passing-in-c.html
The last article actually uses the StringBuilder type in its examples, so you can clearly see what's going on in your case. If you pass in the StringBuilder type by reference you'll get this:
Reference type passed by reference:

As long as you're dealing with reference types (classes, which StringBuilder and String are), there's rarely a point in passing them by reference since no copy will be made anyways.

Non-value types are always passed by reference. The purpose of ref keyword is to let you change the reference to the object inside the method.
You misunderstood the arguments passing completely. Read this article.

Passing arguments by value
By default, arguments in C# are passed by value. This means a copy of the value is created when passed to the method:
class Test
{
static void Foo(int p)
{
p = p + 1; // Increment p by one.
Console.WriteLine(p); // Write p to screen.
}
static void Main()
{
int x = 8;
Foo(x); // Make a copy of x.
Console.WriteLine(x); // x will still be 8.
}
}
Assigning p a new value does not change the contents of variable x, because p and x reside in different memory locations.
Passing a reference-tupe argument by value copies the reference, but not the object. An example in the case of string builder; here Foo sees the same StringBuilder object that main instantiated, but has an independent reference to it. So StrBuild and fooStrBuild are seperate variables that reference the same StringBuilder object:
class Test
{
static void Foo(StringBuilder fooStrBuild)
{
fooStrBuild.Append("testing");
fooStrBuild = null;
}
static void Main()
{
StringBuilder StrBuild = new StringBuilder();
Foo(strBuild);
Console.WriteLine(StrBuild.ToString()); // "testing"
}
}
Because fooStrBuild is a copy of a reference changing its value does not change StrBuild.
Pass by reference
In the following, p and x refer to the same memory locations:
class Test
{
static void Foo(ref int p)
{
p = p + 1; // Increment p by one.
Console.WriteLine(p); // Write p to screen.
}
static void Main()
{
int x = 8;
Foo(ref x); // Make a copy of x.
Console.WriteLine(x); // x is now 9.
}
}
hence the value of p is changed.
Hope this helps.

Related

why pass string doesn't work even string is passed as reference in function? [duplicate]

I know that "string" in C# is a reference type. This is on MSDN. However, this code doesn't work as it should then:
class Test
{
public static void Main()
{
string test = "before passing";
Console.WriteLine(test);
TestI(test);
Console.WriteLine(test);
}
public static void TestI(string test)
{
test = "after passing";
}
}
The output should be "before passing" "after passing" since I'm passing the string as a parameter and it being a reference type, the second output statement should recognize that the text changed in the TestI method. However, I get "before passing" "before passing" making it seem that it is passed by value not by ref. I understand that strings are immutable, but I don't see how that would explain what is going on here. What am I missing? Thanks.
The reference to the string is passed by value. There's a big difference between passing a reference by value and passing an object by reference. It's unfortunate that the word "reference" is used in both cases.
If you do pass the string reference by reference, it will work as you expect:
using System;
class Test
{
public static void Main()
{
string test = "before passing";
Console.WriteLine(test);
TestI(ref test);
Console.WriteLine(test);
}
public static void TestI(ref string test)
{
test = "after passing";
}
}
Now you need to distinguish between making changes to the object which a reference refers to, and making a change to a variable (such as a parameter) to let it refer to a different object. We can't make changes to a string because strings are immutable, but we can demonstrate it with a StringBuilder instead:
using System;
using System.Text;
class Test
{
public static void Main()
{
StringBuilder test = new StringBuilder();
Console.WriteLine(test);
TestI(test);
Console.WriteLine(test);
}
public static void TestI(StringBuilder test)
{
// Note that we're not changing the value
// of the "test" parameter - we're changing
// the data in the object it's referring to
test.Append("changing");
}
}
See my article on parameter passing for more details.
If we have to answer the question: String is a reference type and it behaves as a reference. We pass a parameter that holds a reference to, not the actual string. The problem is in the function:
public static void TestI(string test)
{
test = "after passing";
}
The parameter test holds a reference to the string but it is a copy. We have two variables pointing to the string. And because any operations with strings actually create a new object, we make our local copy to point to the new string. But the original test variable is not changed.
The suggested solutions to put ref in the function declaration and in the invocation work because we will not pass the value of the test variable but will pass just a reference to it. Thus any changes inside the function will reflect the original variable.
I want to repeat at the end: String is a reference type but since its immutable the line test = "after passing"; actually creates a new object and our copy of the variable test is changed to point to the new string.
As others have stated, the String type in .NET is immutable and it's reference is passed by value.
In the original code, as soon as this line executes:
test = "after passing";
then test is no longer referring to the original object. We've created a new String object and assigned test to reference that object on the managed heap.
I feel that many people get tripped up here since there's no visible formal constructor to remind them. In this case, it's happening behind the scenes since the String type has language support in how it is constructed.
Hence, this is why the change to test is not visible outside the scope of the TestI(string) method - we've passed the reference by value and now that value has changed! But if the String reference were passed by reference, then when the reference changed we will see it outside the scope of the TestI(string) method.
Either the ref or out keyword are needed in this case. I feel the out keyword might be slightly better suited for this particular situation.
class Program
{
static void Main(string[] args)
{
string test = "before passing";
Console.WriteLine(test);
TestI(out test);
Console.WriteLine(test);
Console.ReadLine();
}
public static void TestI(out string test)
{
test = "after passing";
}
}
"A picture is worth a thousand words".
I have a simple example here, it's similar to your case.
string s1 = "abc";
string s2 = s1;
s1 = "def";
Console.WriteLine(s2);
// Output: abc
This is what happened:
Line 1 and 2: s1 and s2 variables reference to the same "abc" string object.
Line 3: Because strings are immutable, so the "abc" string object does not modify itself (to "def"), but a new "def" string object is created instead, and then s1 references to it.
Line 4: s2 still references to "abc" string object, so that's the output.
Actually it would have been the same for any object for that matter i.e. being a reference type and passing by reference are 2 different things in c#.
This would work, but that applies regardless of the type:
public static void TestI(ref string test)
Also about string being a reference type, its also a special one. Its designed to be immutable, so all of its methods won't modify the instance (they return a new one). It also has some extra things in it for performance.
Here's a good way to think about the difference between value-types, passing-by-value, reference-types, and passing-by-reference:
A variable is a container.
A value-type variable contains an instance.
A reference-type variable contains a pointer to an instance stored elsewhere.
Modifying a value-type variable mutates the instance that it contains.
Modifying a reference-type variable mutates the instance that it points to.
Separate reference-type variables can point to the same instance.
Therefore, the same instance can be mutated via any variable that points to it.
A passed-by-value argument is a new container with a new copy of the content.
A passed-by-reference argument is the original container with its original content.
When a value-type argument is passed-by-value:
Reassigning the argument's content has no effect outside scope, because the container is unique.
Modifying the argument has no effect outside scope, because the instance is an independent copy.
When a reference-type argument is passed-by-value:
Reassigning the argument's content has no effect outside scope, because the container is unique.
Modifying the argument's content affects the external scope, because the copied pointer points to a shared instance.
When any argument is passed-by-reference:
Reassigning the argument's content affects the external scope, because the container is shared.
Modifying the argument's content affects the external scope, because the content is shared.
In conclusion:
A string variable is a reference-type variable. Therefore, it contains a pointer to an instance stored elsewhere.
When passed-by-value, its pointer is copied, so modifying a string argument should affect the shared instance.
However, a string instance has no mutable properties, so a string argument cannot be modified anyway.
When passed-by-reference, the pointer's container is shared, so reassignment will still affect the external scope.
Above answers are helpful, I'd just like to add an example that I think is demonstrating clearly what happens when we pass parameter without the ref keyword, even when that parameter is a reference type:
MyClass c = new MyClass(); c.MyProperty = "foo";
CNull(c); // only a copy of the reference is sent
Console.WriteLine(c.MyProperty); // still foo, we only made the copy null
CPropertyChange(c);
Console.WriteLine(c.MyProperty); // bar
private void CNull(MyClass c2)
{
c2 = null;
}
private void CPropertyChange(MyClass c2)
{
c2.MyProperty = "bar"; // c2 is a copy, but it refers to the same object that c does (on heap) and modified property would appear on c.MyProperty as well.
}
For curious minds and to complete the conversation:
Yes, String is a reference type:
unsafe
{
string a = "Test";
string b = a;
fixed (char* p = a)
{
p[0] = 'B';
}
Console.WriteLine(a); // output: "Best"
Console.WriteLine(b); // output: "Best"
}
But note that this change only works in an unsafe block! because Strings are immutable (From MSDN):
The contents of a string object cannot be changed after the object is
created, although the syntax makes it appear as if you can do this.
For example, when you write this code, the compiler actually creates a
new string object to hold the new sequence of characters, and that new
object is assigned to b. The string "h" is then eligible for garbage
collection.
string b = "h";
b += "ello";
And keep in mind that:
Although the string is a reference type, the equality operators (== and
!=) are defined to compare the values of string objects, not
references.
Try:
public static void TestI(ref string test)
{
test = "after passing";
}
I believe your code is analogous to the following, and you should not have expected the value to have changed for the same reason it wouldn't here:
public static void Main()
{
StringWrapper testVariable = new StringWrapper("before passing");
Console.WriteLine(testVariable);
TestI(testVariable);
Console.WriteLine(testVariable);
}
public static void TestI(StringWrapper testParameter)
{
testParameter = new StringWrapper("after passing");
// this will change the object that testParameter is pointing/referring
// to but it doesn't change testVariable unless you use a reference
// parameter as indicated in other answers
}
Another way to bypass the string behavior. Use string array of ONE element only and manipulate this element.
class Test
{
public static void Main()
{
string[] test = new string[1] {"before passing"};
Console.WriteLine(ref test);
TestI(test);
Console.WriteLine(ref test);
}
public static void TestI(ref string[] test)
{
test[0] = "after passing";
}
}

How does reference parameter work in a function [duplicate]

I know that "string" in C# is a reference type. This is on MSDN. However, this code doesn't work as it should then:
class Test
{
public static void Main()
{
string test = "before passing";
Console.WriteLine(test);
TestI(test);
Console.WriteLine(test);
}
public static void TestI(string test)
{
test = "after passing";
}
}
The output should be "before passing" "after passing" since I'm passing the string as a parameter and it being a reference type, the second output statement should recognize that the text changed in the TestI method. However, I get "before passing" "before passing" making it seem that it is passed by value not by ref. I understand that strings are immutable, but I don't see how that would explain what is going on here. What am I missing? Thanks.
The reference to the string is passed by value. There's a big difference between passing a reference by value and passing an object by reference. It's unfortunate that the word "reference" is used in both cases.
If you do pass the string reference by reference, it will work as you expect:
using System;
class Test
{
public static void Main()
{
string test = "before passing";
Console.WriteLine(test);
TestI(ref test);
Console.WriteLine(test);
}
public static void TestI(ref string test)
{
test = "after passing";
}
}
Now you need to distinguish between making changes to the object which a reference refers to, and making a change to a variable (such as a parameter) to let it refer to a different object. We can't make changes to a string because strings are immutable, but we can demonstrate it with a StringBuilder instead:
using System;
using System.Text;
class Test
{
public static void Main()
{
StringBuilder test = new StringBuilder();
Console.WriteLine(test);
TestI(test);
Console.WriteLine(test);
}
public static void TestI(StringBuilder test)
{
// Note that we're not changing the value
// of the "test" parameter - we're changing
// the data in the object it's referring to
test.Append("changing");
}
}
See my article on parameter passing for more details.
If we have to answer the question: String is a reference type and it behaves as a reference. We pass a parameter that holds a reference to, not the actual string. The problem is in the function:
public static void TestI(string test)
{
test = "after passing";
}
The parameter test holds a reference to the string but it is a copy. We have two variables pointing to the string. And because any operations with strings actually create a new object, we make our local copy to point to the new string. But the original test variable is not changed.
The suggested solutions to put ref in the function declaration and in the invocation work because we will not pass the value of the test variable but will pass just a reference to it. Thus any changes inside the function will reflect the original variable.
I want to repeat at the end: String is a reference type but since its immutable the line test = "after passing"; actually creates a new object and our copy of the variable test is changed to point to the new string.
As others have stated, the String type in .NET is immutable and it's reference is passed by value.
In the original code, as soon as this line executes:
test = "after passing";
then test is no longer referring to the original object. We've created a new String object and assigned test to reference that object on the managed heap.
I feel that many people get tripped up here since there's no visible formal constructor to remind them. In this case, it's happening behind the scenes since the String type has language support in how it is constructed.
Hence, this is why the change to test is not visible outside the scope of the TestI(string) method - we've passed the reference by value and now that value has changed! But if the String reference were passed by reference, then when the reference changed we will see it outside the scope of the TestI(string) method.
Either the ref or out keyword are needed in this case. I feel the out keyword might be slightly better suited for this particular situation.
class Program
{
static void Main(string[] args)
{
string test = "before passing";
Console.WriteLine(test);
TestI(out test);
Console.WriteLine(test);
Console.ReadLine();
}
public static void TestI(out string test)
{
test = "after passing";
}
}
"A picture is worth a thousand words".
I have a simple example here, it's similar to your case.
string s1 = "abc";
string s2 = s1;
s1 = "def";
Console.WriteLine(s2);
// Output: abc
This is what happened:
Line 1 and 2: s1 and s2 variables reference to the same "abc" string object.
Line 3: Because strings are immutable, so the "abc" string object does not modify itself (to "def"), but a new "def" string object is created instead, and then s1 references to it.
Line 4: s2 still references to "abc" string object, so that's the output.
Actually it would have been the same for any object for that matter i.e. being a reference type and passing by reference are 2 different things in c#.
This would work, but that applies regardless of the type:
public static void TestI(ref string test)
Also about string being a reference type, its also a special one. Its designed to be immutable, so all of its methods won't modify the instance (they return a new one). It also has some extra things in it for performance.
Here's a good way to think about the difference between value-types, passing-by-value, reference-types, and passing-by-reference:
A variable is a container.
A value-type variable contains an instance.
A reference-type variable contains a pointer to an instance stored elsewhere.
Modifying a value-type variable mutates the instance that it contains.
Modifying a reference-type variable mutates the instance that it points to.
Separate reference-type variables can point to the same instance.
Therefore, the same instance can be mutated via any variable that points to it.
A passed-by-value argument is a new container with a new copy of the content.
A passed-by-reference argument is the original container with its original content.
When a value-type argument is passed-by-value:
Reassigning the argument's content has no effect outside scope, because the container is unique.
Modifying the argument has no effect outside scope, because the instance is an independent copy.
When a reference-type argument is passed-by-value:
Reassigning the argument's content has no effect outside scope, because the container is unique.
Modifying the argument's content affects the external scope, because the copied pointer points to a shared instance.
When any argument is passed-by-reference:
Reassigning the argument's content affects the external scope, because the container is shared.
Modifying the argument's content affects the external scope, because the content is shared.
In conclusion:
A string variable is a reference-type variable. Therefore, it contains a pointer to an instance stored elsewhere.
When passed-by-value, its pointer is copied, so modifying a string argument should affect the shared instance.
However, a string instance has no mutable properties, so a string argument cannot be modified anyway.
When passed-by-reference, the pointer's container is shared, so reassignment will still affect the external scope.
Above answers are helpful, I'd just like to add an example that I think is demonstrating clearly what happens when we pass parameter without the ref keyword, even when that parameter is a reference type:
MyClass c = new MyClass(); c.MyProperty = "foo";
CNull(c); // only a copy of the reference is sent
Console.WriteLine(c.MyProperty); // still foo, we only made the copy null
CPropertyChange(c);
Console.WriteLine(c.MyProperty); // bar
private void CNull(MyClass c2)
{
c2 = null;
}
private void CPropertyChange(MyClass c2)
{
c2.MyProperty = "bar"; // c2 is a copy, but it refers to the same object that c does (on heap) and modified property would appear on c.MyProperty as well.
}
For curious minds and to complete the conversation:
Yes, String is a reference type:
unsafe
{
string a = "Test";
string b = a;
fixed (char* p = a)
{
p[0] = 'B';
}
Console.WriteLine(a); // output: "Best"
Console.WriteLine(b); // output: "Best"
}
But note that this change only works in an unsafe block! because Strings are immutable (From MSDN):
The contents of a string object cannot be changed after the object is
created, although the syntax makes it appear as if you can do this.
For example, when you write this code, the compiler actually creates a
new string object to hold the new sequence of characters, and that new
object is assigned to b. The string "h" is then eligible for garbage
collection.
string b = "h";
b += "ello";
And keep in mind that:
Although the string is a reference type, the equality operators (== and
!=) are defined to compare the values of string objects, not
references.
Try:
public static void TestI(ref string test)
{
test = "after passing";
}
I believe your code is analogous to the following, and you should not have expected the value to have changed for the same reason it wouldn't here:
public static void Main()
{
StringWrapper testVariable = new StringWrapper("before passing");
Console.WriteLine(testVariable);
TestI(testVariable);
Console.WriteLine(testVariable);
}
public static void TestI(StringWrapper testParameter)
{
testParameter = new StringWrapper("after passing");
// this will change the object that testParameter is pointing/referring
// to but it doesn't change testVariable unless you use a reference
// parameter as indicated in other answers
}
Another way to bypass the string behavior. Use string array of ONE element only and manipulate this element.
class Test
{
public static void Main()
{
string[] test = new string[1] {"before passing"};
Console.WriteLine(ref test);
TestI(test);
Console.WriteLine(ref test);
}
public static void TestI(ref string[] test)
{
test[0] = "after passing";
}
}

What Is The Difference Between Passing Parameters By Output And By Reference In C#

I have been making an effort on C# methods. There are three ways that parameters can be passed to a C# methods.
Value parameters : This method copies the actual value of an argument into the formal parameter of the function. In this case, changes made to the parameter inside the function have no effect on the argument.
Reference parameters : This method copies the reference to the memory location of an argument into the formal parameter. This means that changes made to the parameter affect the argument.
Output parameters : This method helps in returning more than one value.
I understood above types of passing parameters with below sample codes.
using System;
namespace PassingParameterByReference
{
class MethodWithReferenceParameters
{
public void swap(ref int x)
{
int temp = 5;
x = temp;
}
static void Main(string[] args)
{
MethodWithReferenceParameters n = new MethodWithReferenceParameters();
/* local variable definition */
int a = 100;
Console.WriteLine("Before swap, value of a : {0}", a);
/* calling a function to swap the value*/
n.swap(ref a);
Console.WriteLine("After swap, value of a : {0}", a);
Console.ReadLine();
}
}
}
When the above code is compiled and executed, it produces the following result:
Before swap, value of a : 100
After swap, value of a : 5
With this codes i could understand to pass parameters to methods by reference. And then i examine below code to understand passing parameters to methods by output.
using System;
namespace PassingParameterByOutput
{
class MethodWithOutputParameters
{
public void swap(out int x)
{
int temp = 5;
x = temp;
}
static void Main(string[] args)
{
MethodWithOutputParameters n = new MethodWithOutputParameters();
/* local variable definition */
int a = 100;
Console.WriteLine("Before swap, value of a : {0}", a);
/* calling a function to swap the value */
n.swap(out a);
Console.WriteLine("After swap, value of a : {0}", a);
Console.ReadLine();
}
}
}
When the above code is compiled and executed, it produces the following result:
Before swap, value of a : 100
After swap, value of a : 5
These sample codes make same action with different ways. And i can't understand difference between two approaches.( Passing Parameters To Method By Output And By Reference). Two example's output is the same. What is this small difference?
Output parameters dont have to be initialized before the method is called like it is the case for reference parameters.
int someNum;
someMethod(out someNum); //works
someMethod(ref someNum); //gives compilation error
Furthermore, the Output parameter needs to be set or changed within the method, which is not necessary for reference parameters.
With "Reference" parameters, the value needs to be assigned before a method can use it. X and Y in your examples would have needed to have been declared outside the method.
e.g. int x = 100; int y =200;
With "Output" parameters, the value for your parameters don't have to be assigned a value before you can use them. X and Y could have been declared in your example with no starting values assigned to them.
e.g int x; int y;
Reference and Output parameters are very similar.
The only difference is that ref parameters must be initialized.
int myInt = 1;
SomeMethod(ref myInt); //will work
SomeMethod(out myInt); //will work
int myInt;
SomeMethod(ref myInt); //won't work
SomeMethod(out myInt); //will work
The compiler will actually view the ref and out keywords the same. For example if you cannot have overloaded methods where the only difference is the ref and out keywords.
The following methods signatures will be viewed the same by the compiler, so this would not be a valid overload.
private void SomeMethod(ref int Foo){};
private void SomeMethod(out int Foo){};
An output parameter needs to have it's value changed inside the method otherwise the compiler will throw an error.
The reference parameter may or may not have it's reference (reference objects) changed by the method.
Also value types (types defined in structs) cannot be passed by reference.
See this What's the difference between the 'ref' and 'out' keywords?
The difference is that for an out parameter you have to set it before leaving the method. So even if you dont set it to any value before calling the method the compiler knows that it will get a value during the method call.
Appart from technical differences, to have a good readable code, you should use out when the method has more than one output. And use ref when the method just may update the variable

In C#, is it the same as in Java refering to object creation during methods?

I have a programming competition tomorrow and I have a quick question:
In Java, if you would pass an object in a parameter for a method, you actually got not a copy of the object, but the actual object.
Is it the same as C#?
public static void PunchyManager(string[] inputArray, ref int a, ref int b)
{
string[] tempStrArray = inputArray;
}
If I do that will I basically make a pointer to inputArray, instead of having a copy?
Just a quick question, thanks!
In regard to your basic question in relation to Java Yes.
More generally Yes and no. Reference types (classes) are passed by reference which is like a single pointer. For something that can truly modify references outside the caller you should use the ref keyword even on reference types. This is similiar to a double pointer (assuming we are referring to pointers as they work in C for our pointer analogies).
class RefRefExample
{
static void Method(ref string s)
{
s = "changed";
}
static void Main()
{
string str = "original";
Method(ref str);
// str is now "changed"
}
}
In the above example if we passed str without using the ref keyword we would reassign the local reference of s instead of the original reference of str. By passing our reference by reference we can modify the original reference outside of the function as well. References themselves are still copied by value (but the copied reference still points to the same value) without the ref keyword.
http://msdn.microsoft.com/en-us/library/14akc2c7(v=vs.80).aspx
For practical usage in the scenario you are describing the modern C# idiom usually uses lists and they will likely be much faster to use as far as programming in your competition:
public static void PunchyManager(List<string> inputList, ref int a, ref int b)
{
var tempList = new List<string>();
foreach (var item in inputList)
tempList.Add(item);
}
Working on the original input list would modify objects through the reference so you would be affecting the original values outside of the method whereas the templList is a copy - Lists are very convenient.
Furthermore you can convert them back to Arrays using .ToArray()
*edit Oh, you wish to know if it is the same in c# as java, your wording was a bit off.
Correct, if you do
public static void main(String[] args)
{
int myArray[] = new int[1];
test(myArray);
System.out.println(myArray[0]);
}
public void test(int[] array)
{
array[0] = 1;
}
You will get an output of 1
In CLR there are two kinds of objects:
Reference types (also known as just "objects")
Value types (also known as "structures" or "structs", even they are technically objects too).
The difference between them is that "objects" are located on heap, when "structs" are located on stack.
Types like Int32, Int64, Float, Double, etc are value types (structs). You can also define your own structure:
public struct MyStruct { ... }
Therefore, when you pass a "struct" around it is passed by copying the value.
Example:
int x = 5; //creates a value type on stack
int y = x; //makes a copy so now we have two objects on stack, not just one
"Objects" are passed by reference.
object x = new Object(); //create an object, x holds a reference to this object
object y = x; // y now holds a reference to the same object x has a reference to.
When you pass reference types around you generally don't need to use a ref keyword. However, if you want to pass a reference to a value type instance you may want to use this keyword.
Yes, class instances are passed as references in C#. If you want to pass value type (like Int32) as reference you need to use ref keyword.
Thing is, If you pass the parameter with keyword ref, modification of the variable inside the method will be reflected to caller as well. This is applicable to even struct(exmple int). But for struct or class, if you pass the parameter with out ref/out, this will be assumed as pass by value, which means, modification inside the method cannot be reflected to caller for structs. For classes, modification will be reflected to caller still without passing with out ref. BUT, StringBuilder sb = new StringBuilder() statement ask the sb to point to this one (an newly created new StringBuilder()). So reference knot will be moved from one which was pointed in the caller to new StringBuilder() in the callee. This has to be remembered always.
Pass by value with ref:
static void Main(string[] args)
{
StringBuilder y = new StringBuilder();
y.Append("hello");
Foo(ref y);
Console.WriteLine(y);
}
private static void Foo(ref StringBuilder y)
{
StringBuilder sb = y;
sb.Append("99");
}
o/p : hello99
Pass by value without ref:
static void Main(string[] args)
{
StringBuilder y = new StringBuilder();
y.Append("hello");
Foo(y);
Console.WriteLine(y);
}
private static void Foo(StringBuilder y)
{
StringBuilder sb = new StringBuilder
sb.Append("99");
}
o/p : hello
To assign something different to your array you'd want to have the parameter use the 'ref' keyword.
http://msdn.microsoft.com/en-us/library/szasx730(v=vs.71).aspx

What is the use of "ref" for reference-type variables in C#?

I understand that if I pass a value-type (int, struct, etc.) as a parameter (without the ref keyword), a copy of that variable is passed to the method, but if I use the ref keyword a reference to that variable is passed, not a new one.
But with reference-types, like classes, even without the ref keyword, a reference is passed to the method, not a copy. So what is the use of the ref keyword with reference-types?
Take for example:
var x = new Foo();
What is the difference between the following?
void Bar(Foo y) {
y.Name = "2";
}
and
void Bar(ref Foo y) {
y.Name = "2";
}
You can change what foo points to using y:
Foo foo = new Foo("1");
void Bar(ref Foo y)
{
y = new Foo("2");
}
Bar(ref foo);
// foo.Name == "2"
There are cases where you want to modify the actual reference and not the object pointed to:
void Swap<T>(ref T x, ref T y) {
T t = x;
x = y;
y = t;
}
var test = new[] { "0", "1" };
Swap(ref test[0], ref test[1]);
Jon Skeet wrote a great article about parameter passing in C#. It details clearly the exact behaviour and usage of passing parameters by value, by reference (ref), and by output (out).
Here's an important quote from that page in relation to ref parameters:
Reference parameters don't pass the
values of the variables used in the
function member invocation - they use
the variables themselves. Rather than
creating a new storage location for
the variable in the function member
declaration, the same storage location
is used, so the value of the variable
in the function member and the value
of the reference parameter will always
be the same. Reference parameters need
the ref modifier as part of both the
declaration and the invocation - that
means it's always clear when you're
passing something by reference.
Very nicely explained here :
http://msdn.microsoft.com/en-us/library/s6938f28.aspx
Abstract from the article:
A variable of a reference type does not contain its data directly; it
contains a reference to its data. When you pass a reference-type
parameter by value, it is possible to change the data pointed to by
the reference, such as the value of a class member. However, you
cannot change the value of the reference itself; that is, you cannot
use the same reference to allocate memory for a new class and have it
persist outside the block. To do that, pass the parameter using the
ref or out keyword.
When you pass a reference type with the ref keyword, you pass the reference by reference, and the method you call can assign a new value to the parameter. That change will propagate to the calling scope. Without ref, the reference is passed by value, and this doesn't happen.
C# also has the 'out' keyword which is a lot like ref, except that with 'ref', arguments must be initialized before calling the method, and with 'out' you must assign a value in the receiving method.
It allows you to modify the reference passed in. e.g.
void Bar()
{
var y = new Foo();
Baz(ref y);
}
void Baz(ref Foo y)
{
y.Name = "2";
// Overwrite the reference
y = new Foo();
}
You can also use out if you don't care about the reference passed in:
void Bar()
{
var y = new Foo();
Baz(out y);
}
void Baz(out Foo y)
{
// Return a new reference
y = new Foo();
}
Another bunch of code
class O
{
public int prop = 0;
}
class Program
{
static void Main(string[] args)
{
O o1 = new O();
o1.prop = 1;
O o2 = new O();
o2.prop = 2;
o1modifier(o1);
o2modifier(ref o2);
Console.WriteLine("1 : " + o1.prop.ToString());
Console.WriteLine("2 : " + o2.prop.ToString());
Console.ReadLine();
}
static void o1modifier(O o)
{
o = new O();
o.prop = 3;
}
static void o2modifier(ref O o)
{
o = new O();
o.prop = 4;
}
}
In addition to the existing answers:
As you asked for the difference of the 2 methods: There is no co(ntra)variance when using ref or out:
class Foo { }
class FooBar : Foo { }
static void Bar(Foo foo) { }
static void Bar(ref Foo foo) { foo = new Foo(); }
void Main()
{
Foo foo = null;
Bar(foo); // OK
Bar(ref foo); // OK
FooBar fooBar = null;
Bar(fooBar); // OK (covariance)
Bar(ref fooBar); // compile time error
}
A parameter in a method seems to be always passing a copy, the question is a copy of what. A copy is done by a copy constructor for an object and since all variables are Object in C#, i believe this is the case for all of them. Variables(objects) are like people living at some addresses. We either change the people living at those addresses or we can create more references to the people living at those addresses in the phone book(make shallow copies). So, more than one identifier can refer to the same address. Reference types desire more space, so unlike value types that are directly connected by an arrow to their identifier in the stack, they have value for another address in the heap( a bigger space to dwell). This space needs to be taken from the heap.
Value type:
Indentifier(contains value =address of stack value)---->Value of value type
Reference type:
Identifier(contains value=address of stack value)---->(contains value=address of heap value)---->Heap value(most often contains addresses to other values), imagine more arrows sticking in different directions to Array[0], Array[1], array[2]
The only way to change a value is to follow the arrows. If one arrow gets lost/changed in the way the value is unreachable.
Reference Variables carry the address from one place to another so any updation on them at any place will reflect on all the places THEN what is the use of REF.
Reference variable (405) are good till no new memory is allocated to the reference variable passed in the method.
Once new memory allocate (410) then the value change on this object (408) will not reflect everywhere.
For this ref comes. Ref is reference of reference so whenever new memory allocate it get to know because it is pointing to that location therefore the value can be shared by everyOne. You can see the image for more clearity.

Categories

Resources