views:

351

answers:

8

Hello,

I have two forms (Form1 and Form2). On Form1 there is a 'public int i' variable, which is set to value 1 in Form1 constructor. Then I open Form2 from Form1 with this code:

Form2 f2 = new Form2(ref i);
f2.ShowDialog();

The constructor of Form2 looks like this:

public int i;
public Form2(ref int x)
{
    InitializeComponent();
    i = x;
}

Then I set variable i on Form2 to value 2 and close Form2. Now I would expect the variable i on Form1 to have value 2 (because of 'ref' keyword by passing parameters), but the value is still 1. What am I doing wrong and why is ref keyword not working in my example?

Thanks

+5  A: 

The "ref" modifier only makes any difference during the constructor call itself. It's only associated with that parameter... and after the constructor has finished, that parameter doesn't exist any more.

When you perform the assignment:

i = x;

That is just copying the value. It's not associating the variable i with x in any other way.

As a general rule of thumb: if you don't change the value of the parameter within the method/constructor (which you don't in your example), the ref modifier isn't doing anything.

You can't do what you want to do: you can't make a field (Form2.i in this case) an alias of some other variable.

Jon Skeet
I'd like to add that Form2 already exposes a public int i, so he should: remove the parameter from the constructor, set the field with f2.i = i; and after the ShowDialog() read it back with i = f2.il
configurator
I'd really hope that the real code *didn't* have a public field though... and that the class wasn't really called Form2, either :)
Jon Skeet
A: 
i = x;

This statement is copying the value of i to the value of x. To change x you need to actually assign a value to it in the constructor. eg.

x=2;
Ash
A: 

the ref keyword scope is only within the declaring method: Form2 constructor. Once that method exits, i in form1 and i in form2 are no longer linked (specially because they are of ValueType)

najmeddine
+3  A: 

What's actually happening.

  1. You create an object1 with a integer member named "i"
  2. You pass a reference to "i" into a new object constructor. The reference to "i" is called "x".
  3. You copy the value of "x" into a variable in the second object, also called "i".
  4. You exit object2's constructor. The reference to object1.i ends here.
  5. You modify object2.i (which is a copy of object1.i, but not a reference, pointer, or link). object1.i is not modified.

There are many ways to accomplish what you want, either with events, or by passing in an object that will be shared between object1 and object2.

Class Form1
{
    Object i = new Object();
    ...
    public void DoSomething()
    {
        Form2 f = new Form2(i);
        f.Show();
    }
}

This would probably be the easiest way to accomplish what you're going for.

C. Ross
I thought that if pass integer with ref keyword, that it is the same thing as passing object. Thanks for clearingthat up, it works now.
_simon_
A: 

I don't know your reasoning behind doing it that way but I suspect it would be a much better idea to return a value from your dialog form and use that to set the variable in the calling class. You would be adding unnecessary coupling to your forms otherwise.

Martin
How can I return value from Form2 to Form1?
_simon_
A: 

I agree with Martin that this type of solution would add unnecessary coupling, but if you still insist on having it tied like this, I think using a simple pointer would do the trick.

class Form1 {  
  public int i;
  public void doSomething(){
    Form2 f = new Form2(&i);
    f.showDialog();
  }
}

Then in Form2 you just work with that pointer.

class Form2 {
  public int *i;
  public Form2(int *r){
    InitializeComponent();
    i = r;
  }
  public void setI(int v){
    *i = v;
  }
  public int getI(){
    return *i;
  }
}

Remember to keep in mind memory management with all this.

dharga
A: 

Thanks for answers...

For now, I found three ways how to get back variable from Form2 to Form1:

  • instead of normal integer, pass an object between forms
  • in Form1 I could put 'private int myVariable' and property 'public int MyVariable' with get and set methods. Then I could pass my whole Form1 to Form2's constructor, where I can access Form1.MyVariable property
  • pointer

Is there any other option? Which of this three options is better? (In my example I need access to only one integer in Form1 from Form2)

Thanks

_simon_
A: 

If you really want to be able to set a variable in Form1 from within Form2 you could use a callback method. (i.e. pass in the address of a method that sets the Form1 variable and runs it from Form2)

Something like this:

public partial class Form1 : Form
{
    public delegate void FormReturn(string s);
    private string var1;

    public Form1()
    {
        InitializeComponent();
    }

    private void button1_Click(object sender, EventArgs e)
    {
        var frm = new Form2(ReturnFunc);
        frm.ShowDialog();
    }

    protected void ReturnFunc(string text)
    {
        var1 = text;
    }
}

public partial class Form2 : Form
{
    private Form1.FormReturn returnFunc;

    public Form2(Form1.FormReturn del)
    {
        InitializeComponent();
        returnFunc = del;
    }

    private void btnClose_Click(object sender, EventArgs e)
    {
        returnFunc.Invoke(txtText.Text);
        Close();
    }
}

Major overkill though. You could just set a public property on form1.

Martin