0

I have created a class which passes a string parameter in the constructor. I change the value of the parameter in the constructor. When the control is back on my original class, the value is not changed. I expect it to change - please help

        string NewNodeName = "";
        AddNode NewNodeFrm = new AddNode( NewNodeName);

        NewNodeFrm.ShowDialog();
        if (NewNodeFrm.DialogResult.Equals(true))
        {
           MessageBox.Show(NewNodeName);
        }

In class called

public partial class AddNode : Window
{
    private string NodeName;

    public AddNode(ref string ANodeName)
    {
        NodeName = ANodeName;
        NodeName = "Fred";

        InitializeComponent();
    }
user2837961
  • 1,505
  • 3
  • 27
  • 67
  • 1
    `DialogResult.Equals(true)` - that's weird, where did you learned that? – Sinatr Jan 29 '15 at 14:55
  • 2
    When you call a method with a `ref` parameter, it should complain unless you also call with `ref`...? Also, you don't assign `ANodeName`. – crashmstr Jan 29 '15 at 14:56
  • 3
    By the way, it is highly unusual to have a constructor that mutates inbound parameters/variables. A constructor should construct/initialize a new object instance, not mutate other objects! – stakx - no longer contributing Jan 29 '15 at 14:57
  • 1
    Possibly relevant [old question of mine](http://stackoverflow.com/questions/2940007/saving-a-reference-to-a-int) that asks a similar question with `int`s. – Scott Chamberlain Jan 29 '15 at 15:01

3 Answers3

4

When you write NodeName = "Fred"; you are changing what NodeName is referring to. That's because NodeName itself is not a ref string.

Bathsheba
  • 231,907
  • 34
  • 361
  • 483
2

It's worth baring in mind that string is an immutable reference type which is implemented in a way to give it the occasional appearance of being a value type. So when you do this:

NodeName = ANodeName;

You're creating a copy, not a reference.

If you did something like this:

        Foo NewNodeName = new Foo();
        AddNode NewNodeFrm = new AddNode(ref NewNodeName);
        MessageBox.Show(NewNodeName.ToString());

And:

    public class Foo
    {
        private int _a = 0;

        public int BAR { get { return _a; } set { _a = value; } }
    }

    public class AddNode
    {
        private Foo NodeName;

        public AddNode(ref Foo ANodeName)
        {
            NodeName = ANodeName;
            NodeName.BAR = 30;
        }
    }

Then this would be fine, the changes would be visible to the caller since you're working on the same object in the AddNode method. In fact you don't need to use the "ref" keyword (pass by reference) in this case as we're not creating a new instance of Foo in the AddNode method.

Jeb
  • 3,689
  • 5
  • 28
  • 45
  • The fact that a string "acts like a value type" does not matter at all for this. Had you been working with objects doing `NodeName = ANodeName; NodeName = new object()` would still not affect `ANodeName`. – Scott Chamberlain Jan 29 '15 at 15:07
  • He was expecting NewNodeName to return from the AddNode method with "Fred". I'm making the OP aware that this won't happen due to a new string instantiation when the assignment "NodeName = ANodeName;" is made. – Jeb Jan 29 '15 at 15:10
  • I know that, but that happening has nothing to do with the object you are working with being a reference type or a value type. – Scott Chamberlain Jan 29 '15 at 15:11
  • Ah I'm with you now!; if it were an object, same thing. Good point. I think my last sentence is probably the most accurate description of what is happening! – Jeb Jan 29 '15 at 15:16
  • String is *not* dealt with like a value type. It's dealt with like a reference type, because it's a reference, not a value. Nothing about it behaves in any way like a value instead of a reference. It's *immutable*, rather than being *mutable*, which has *nothing* to do with value/reference semantics. This answer is 100% wrong. – Servy Jan 29 '15 at 15:33
  • Point taken Servy - in fact my link to Marc Gravell's good answer and just stating the assigning creating a new instance will surely help the OP understand why it's not working? I've lessened the "blow" of insinuating string is "dealt with" like a value type here. – Jeb Jan 29 '15 at 15:44
  • Open to more suggestions - is this acceptable at the moment? – Jeb Jan 29 '15 at 15:50
  • Don't open with the blatant lie that "strings behave like value types". They don't behave like value types. They behave like reference types. It behaves like an immutable type because it's immutable. It would behave like a mutable type if it were mutable. You're also mis-representing Marc's post in the process. Your last paragraph is also not *wrong*, but it's not really explaining clearly what's going on. – Servy Jan 29 '15 at 16:19
  • Servy: I think your accusation is rather harsh; I don't ever intend to lie, and try and be altruistic on this forum. Being a high reputation member, I think you have a responsibility to try and motivate users like myself by explaining what could be made better in posts by users like myself instead of a barrage of criticism. I've changed my answer, hopefully better and I'm always listening for ways to improve on them. – Jeb Jan 29 '15 at 16:44
0

You can overcome using an object . Maybe pass in this:

Public class NodeName
{

       public string Name{get;set;}

}

Then in your constructor set a local variable and change the name

public AddNode : Window
{
    Private NodeNme name;
    Public  AddNode(NodeNme name)
   {
        this.name = name;
        this.name.Name = "Fred";
   }
}

Because your are passing and storing a ref type this will reflect the changes inside your class and in your consumer.

Noel
  • 567
  • 1
  • 4
  • 11