Reputation: 10191
I have just written a function and I don't understand why I'm getting the result I am:
private void ReplaceIfEmpty(string originalValue, string newValue)
{
if (string.IsNullOrWhitespace(originalValue))
{
originalValue= newValue;
}
}
When I call this function the originalValue is not updated. My understanding is that a string is a class, therefore it's a reference type, therefore the value I pass in should be updated. Can you explain why it isn't?
Upvotes: 1
Views: 418
Reputation: 659974
You passed a reference to a string. You did not pass a reference to a variable. If you want to change a variable then you do it like this:
private void ReplaceIfEmpty(ref string originalValue, string newValue) ...
The difference is frequently confusing to people. Think about it this way. Instead of imagining a string, imagine two houses. Now imagine two pieces of paper that have the addresses of those houses; those are references to the houses. And now imagine four drawers that each contain a piece of paper. The drawers are labelled p, q, x and y:
void M(House x, House y)
{
x = y;
}
...
House p = new House("123 Sesame Street");
House q = new House("1600 Pennsylvania Avenue");
M(p, q);
What does this program do? You put a piece of paper that says "123 Sesame Street" in drawer p. You put a piece of paper that says "1600 Pennsylvania Avenue" in drawer q.
You make a photocopy of the paper in drawer p and put the copy in drawer x. You make a photocopy of the paper in drawer q and put the copy in drawer y. And then you call M. M makes a photocopy of what's in drawer y and puts it in drawer x. Drawer p is not affected.
Now consider this case:
void M(ref House r, House s)
{
r = s;
}
...
House p = new House("123 Sesame Street");
House q = new House("1600 Pennsylvania Avenue");
M(ref p, q);
What does this program do? You put a piece of paper that says "123 Sesame Street" in drawer p. You put a piece of paper that says "1600 Pennsylvania Avenue" in drawer q.
You put a sticky note on drawer p that says "this drawer is also called r".
You make a photocopy of the paper in drawer q and put the copy in drawer s.
And then you call M. M makes a photocopy of what's in drawer s and puts it in drawer r, which is the same as drawer p.
Make sense?
Upvotes: 7
Reputation: 160852
You are not changing the value of variable that you passed as the parameter originalValue
, you are trying to assign a new instance to it, which for references means that the variable points to a new reference - to update a reference you need to pass the string by ref - by default references are passed by value so the variable that you pass never gets updated:
private void ReplaceIfEmpty(ref string originalValue, string newValue)
{
if (string.IsNullOrWhitespace(originalValue))
{
originalValue = newValue;
}
}
A much better approach would be to just return the new string instead:
private string ReplaceIfEmpty(string originalValue, string newValue)
{
if (string.IsNullOrWhitespace(originalValue))
return newValue;
else
return originalValue;
}
Or even more convenient make it an extension method:
public static string ReplaceIfEmpty(this string originalValue,
string replaceValue)
{
if (string.IsNullOrWhitespace(originalValue))
return replaceValue;
else
return originalValue;
}
Upvotes: 5
Reputation: 1499860
This has nothing to do with reference types vs value types really.
You're changing the value of a parameter:
originalValue= newValue;
For "normal" parameters which don't have the ref
or out
modifier, that change will never be visible.
See my article on parameter passing for more information, along with my article on reference types and value types to make sure you understand why sometimes it "looks" like reference types are passed by reference by default. (They're not: all arguments are passed by value by default, it's just that for reference types, the argument value is a reference, not an object, so changes made to the object are still visible from the caller.)
So you could make originalValue
a ref
parameter - but it would be better to make the method return a string
instead. I'm generally reluctant to use ref
parameters; code is usually easier to understand without them.
Upvotes: 19
Reputation: 245399
When you do the following assignemnt:
originalValue = newValue;
You're not changing the string value that was referenced by originalValue
, you're changing the value of originalValue
to point to the same location as newValue
.
Strings are immutable and can't be modified after they're set, only re-assigned.
Upvotes: 0