Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Passing string ByVal in VB.NET AND C#

So strings are reference types right? My understanding is a reference to the string in the heap is passed even when you pass the string ByVal to a method.

Sooo.....

String myTestValue = "NotModified";
TestMethod(myTestValue);
System.Diagnostics.Debug.Write(myTestValue); /* myTestValue = "NotModified" WTF? */

private void TestMethod(String Value)
{
    Value = "test1";
}

Alternatively

Dim myTestValue As String = "NotModified"
TestMethod(myTestValue)
Debug.Print(myTestValue) /* myTestValue = "NotModified" WTF? */

Private Sub TestMethod(ByVal Value As String)
    Value = "test1"
End Sub

What am I missing? And what is going on under the hood? I would have bet my life that the value would have changed....

like image 449
Maxim Gershkovich Avatar asked Mar 02 '11 04:03

Maxim Gershkovich


People also ask

What is ByVal in VB net?

Specifies that an argument is passed by value, so that the called procedure or property cannot change the value of a variable underlying the argument in the calling code. If no modifier is specified, ByVal is the default.

What is the difference between ByRef and ByVal when passing data?

ByRef = You give your friend your term paper (the original) he marks it up and can return it to you. ByVal = You give him a copy of the term paper and he give you back his changes but you have to put them back in your original yourself. As simple as I can make it.

Is ByRef faster than ByVal?

With a large Byte() array, ByVal is faster than ByRef , but it's also negligible.


3 Answers

Reference types are passed "reference by value" in .NET. This means that assigning a different value to the actual parameter does not actually change original value (unless you use ByRef/ref). However, anything you do to change the actual object that gets passed in will change the object that the calling method refers to. For example, consider the following program:

void Main()
{
    var a = new A{I=1};
    Console.WriteLine(a.I);
    DoSomething(a);
    Console.WriteLine(a.I);
    DoSomethingElse(a);
    Console.WriteLine(a.I);
}

public void DoSomething(A a)
{
    a = new A{I=2};
}

public void DoSomethingElse(A a)
{
    a.I = 2;
}

public class A
{
    public int I;
}

Output:

1
1
2

The DoSomething method assigned its a parameter to have a different value, but that parameter is just a local pointer to the location of the original a from the calling method. Changing the pointer's value did nothing to change the calling method's a value. However, DoSomethingElse actually made a change to one of the values on the referenced object.

Regardless of what the other answerers say, string is not exceptional in this way. All objects behave this way.

Where string differs from many objects is that it is immutable: there aren't any methods or properties or fields on string that you can call to actually change the string. Once a string is created in .NET, it is read-only.

When you do something like this:

var s = "hello";
s += " world";

... the compiler turns this into something like this:

// this is compiled into the assembly, and doesn't need to be set at runtime.
const string S1 = "hello"; 
const string S2 = " world"; // likewise
string s = S1;
s = new StringBuilder().Append(s).Append(S2).ToString();

This last line generates a new string, but S1 and S2 are still hanging around. If they are constant strings built into the assembly, they'll stay there. If they were created dynamically and have no more references to them, the garbage collector can de-reference them to free up memory. But the key is to realize that S1 never actually changed. The variable pointing to it just changed to point to a different string.

like image 182
StriplingWarrior Avatar answered Sep 20 '22 05:09

StriplingWarrior


Everything is passed by value unless you specify otherwise. When you're passing a String, you're actually passing a reference by value.

For Strings, this doesn't make much difference, as Strings are immutable. Meaning you never get to modify the string you receive. For other classes, though, you can modify an object passed by value (unless, like String, it is immutable). What you can't do, and what passing by reference allows you to do, is modify the variable you're passing.

Example:

Public Class Example
    Private Shared Sub ExampleByValue(ByVal arg as String)
        arg = "ByVal args can be modifiable, but can't be replaced."
    End Sub

    Private Shared Sub ExampleByRef(ByRef arg as String)
        arg = "ByRef args can be set to a whole other object, if you want."
    End Sub

    Public Shared Sub Main()
        Dim s as String = ""
        ExampleByValue(s)
        Console.WriteLine(s)  ''// This will print an empty line
        ExampleByRef(s)
        Console.WriteLine(s)  ''// This will print our lesson for today
    End Sub
End Class

Now, this should be used very sparingly, because by-value is the default and expected. Particularly in VB, which doesn't always make it clear when you're passing by reference, it can cause a lot of problems when some method starts unexpectedly mucking around with your variables.

like image 22
cHao Avatar answered Sep 21 '22 05:09

cHao


All types, including reference types are passed by value by default, as in your example, which means that a copy of the reference is passed. So, so no matter what, re-assigning an object like that would have no effect when you pass it by value. You're just changing what the copy of the reference points to. You must explicitly pass by reference to achieve what you're trying to do.

It's only when you modify an object that's passed by value can the effect be seen outside of the method. Of course strings are immutable, so this doesn't really apply here.

like image 38
Adam Rackis Avatar answered Sep 20 '22 05:09

Adam Rackis