-2

I'm looking for some clarification and confirmation that this is indeed doing nothing.

Say I have an object

public class Person
{
    public string Name { get; set; }
}

and I am going to use this object and for some reason it has to be initialized, which should happen in the constructor but for this example its going to happen in a call to an initialize function

public class myClass
{
    private void doingSomething()
    {
        Person p = new Person();
        Initialize(p);
    }

    private void Initialize(Person person)
    {
        person.Name = "";
    }
}

This is just a waste correct. If I really wanted to change the values doesn't it have to be passed using ref, out, or returning a different Person?

If I'm wrong i'd appreciate an explanation. I found this while looking through some old code and feel confused because I can't believe it's there.

Marsh
  • 188
  • 2
  • 10
  • What happened when you actually ran the code? – Servy Oct 04 '17 at 16:04
  • it appears to have changed the value, and now i'm even more confused – Marsh Oct 04 '17 at 16:09
  • What do you *think* should be happening? Why? Initializing an object in another method like this is certainly unusual and not a great design, but what's your question? – David Oct 04 '17 at 16:09
  • I think that it should be going out of scope at the end of the initialize method and the original object wouldn't at all be changed. I see that with an integer the value does not change after a similarly structured test. So my question now is why do the different types behave differently? – Marsh Oct 04 '17 at 16:14
  • http://www.albahari.com/valuevsreftypes.aspx I bet person.Name has changed BUT p Person did not. you passed by value and not by ref so p cannot change. are you saying that p.Name = ""? that would also be correct as I see that you have not changed p.Name to anything so it appears to be altering. if you set person.Name = "something" then p.Name will not change to "something" – Aaron. S Oct 04 '17 at 16:18
  • Person Name, I am assuming is a string? the default value for string is and empty string – Aaron. S Oct 04 '17 at 16:19
  • if i set p.Name = "something", it is indeed changed after the call to initialize. – Marsh Oct 04 '17 at 16:24

1 Answers1

1

doesn't it have to be passed using ref, out, or returning a different Person?

Nope.

Consider the stack and the heap. For primitive values (integers are a good example) they just exist on the stack. When they're passed to a method, a copy of them is supplied to that next frame on the stack.

For reference types however, what gets passed to the next frame on the stack? The reference does. Consider it like a "pointer". A simple value which indicates where in the heap the actual object is.

This is only ever invoked once in your example:

new Person()

So only one instance of Person exists in memory. The "pointer" to that instance was copied into the stack frame. If you change the value of the "pointer" itself:

private void Initialize(Person person)
{
    person = new Person();
}

Then no effect would come to the original instance. But that's not what happened. The "pointer" was followed and the instance was changed:

person.Name = "";

The variable person was unaffected by this statement. No operation was made to modify it. But a property on the object in memory that the person variable points to was modified. That change is visible anywhere a reference to that object exists, inside or outside the method, anywhere in the system.

David
  • 208,112
  • 36
  • 198
  • 279
  • Thanks a ton for the deeper explanation. I feel lame for overlooking value and reference types this entire time. This is also a nice page if someone else comes along, helps visualize. [link](http://www.tutorialsteacher.com/csharp/csharp-value-type-and-reference-type) – Marsh Oct 04 '17 at 16:21
  • umm no, this answer is not correct at all. your theory is not correct, good try though. I tested your theory with a code example. if your theory were true then there would be all kinds of programs with issues out there. the default value for a string is an empty string. he is setting the value to an empty string and wondering why it changed the original value. they are both empty strings so it appears to have changed. use a real value and you will see no persistence. – Aaron. S Oct 04 '17 at 16:23
  • @Aaron.S: Your test appears to be flawed. This behavior is indeed correct and by design. – David Oct 04 '17 at 16:26
  • @Marsh your link is spot on, if you assign a real value instead of an empty string to person.Name then you would see that p.Name value does not get changed. because you used an empty string and the default value is an empty string it appears to be changing – Aaron. S Oct 04 '17 at 16:26
  • I've just been testing this. Set p.Name = "m" prior to a call to a function that changes p.Name = "j" and show a messagebox after the call to see what p.Name is and it comes back as "j" – Marsh Oct 04 '17 at 16:28
  • 2
    @Aaron.S: How about just testing it and observing the actual behavior?: https://dotnetfiddle.net/9gu5YL – David Oct 04 '17 at 16:30
  • Passing by Reference: When you pass a reference type variable from one method to another, it doesn't create a new copy; instead, it passes the address of the variable. If we now change the value of the variable in a method, it will also be reflected in the calling method. @David – Aaron. S Oct 04 '17 at 16:31
  • Passing by Value: When you pass a value type variable from one method to another method, the system creates a separate copy of a variable in another method, so that if value got changed in the one method won't affect on the variable in another method. – Aaron. S Oct 04 '17 at 16:31
  • @Aaron.S: You're making mutually exclusive and conflicting assertions. Was there a point in all of this? – David Oct 04 '17 at 16:33
  • what am I missing here? help me @David understand? I cannot find anywhere anything to support what you are stating is true BUT Marsh clearly has an example that is contrary to what is stated everywhere. is this a flaw in whatever version of c# he is using? I tested his code using VS2017 and my copied code does not exhibit this – Aaron. S Oct 04 '17 at 16:34
  • @Aaron.S: `"I cannot find anywhere anything to support what you are stating is true"` - Well, aside from observing the actual behavior in the example provided, there's *your own source* that you quoted: `"When you pass a reference type variable from one method to another, it doesn't create a new copy; instead, it passes the address of the variable. If we now change the value of the variable in a method, it will also be reflected in the calling method."` - You've *already found* the information you're looking for. Whatever test you claim to be conducting is clearly flawed. – David Oct 04 '17 at 16:36
  • yes I see now, thank you – Aaron. S Oct 04 '17 at 16:40