Sheikh Rahat Ali
Sheikh Rahat Ali

Reputation: 1333

C# ref Confusion

I have a confusion that when i pass a variable by refrence in the constructor of another class and after passing that object by refrence i recreate the refrence object with the new keyword.

Now the class in which i have passed the refrenced object dosen't reflect the updated data. An exabple of the above problem is shown below:

Object to be passed by Refrence:

public class DummyObject
{
    public string Name = "My Name";

    public DummyObject()
    { }
}

Class which is passing the Refrence:

public partial class Form1 : Form
{
    // Object to be passed as refrence
    DummyObject dummyObject = new DummyObject();

    public Form1()
    {
        InitializeComponent();
    }

    private void button1_Click(object sender, EventArgs e)
    {
        // assigning value
        dummyObject.Name = "I am Dummy";

        // Passing object
        Form2 frm = new Form2(ref dummyObject);
        frm.Show();
    }

    private void button2_Click(object sender, EventArgs e)
    {
        // Displaying Name
        MessageBox.Show(this.dummyObject.Name);
    }

    private void button3_Click(object sender, EventArgs e)
    {
        // Assigning new object
        this.dummyObject = new DummyObject();

        // Changing Name Variable
        this.dummyObject.Name = "I am Rechanged";

        // Displaying Name
        MessageBox.Show(this.dummyObject.Name);
    }
}

Class to which Object is passed by Reference:

public partial class Form2 : Form
{
    private DummyObject dummyObject = null;

    public Form2(ref DummyObject DummyObject)
    {
        InitializeComponent();

        this.dummyObject = DummyObject;
        this.dummyObject.Name = "I am Changed";
    }

    private void button2_Click(object sender, EventArgs e)
    {
        MessageBox.Show(this.dummyObject.Name);
    }
}

whn i reaasign the object in Form 1 and cdisplay its value in form 2 it still displays "I am Changed" instead of "I am Rechanged".

How to keep the data synchronized?

Upvotes: 2

Views: 309

Answers (6)

Sheikh Rahat Ali
Sheikh Rahat Ali

Reputation: 1333

I have reconsidered my application by using property as suggested by Adam Robinson for synchronization purposes. Now my code have been changed as shown below and producing the desired results.

Class which contains the data needed to be Synchronized:

public class DummyObject
{
    public string Name = "My Name is this.";        

    public DummyObject()
    { }        
}

Class creating new Inctance & reassigning it to Property:

public partial class Form1 : Form
{
    // Instance of DummyObject
    DummyObject dummyObject = new DummyObject();

    // Create Instance of Form2
    Form2 frm2 = new Form2();

    public Form1()
    {
        InitializeComponent();            

        // Assign DummyObject to Form2.DummyObject property
        frm2.DummyObject = this.dummyObject;

        // Change Form2 DummyObject.Name
        frm2.DummyObject.Name = "I am changed for Form2.";

        // Display Form2
        frm2.Show();
    }

    private void button1_Click(object sender, EventArgs e)
    {
        MessageBox.Show(this.dummyObject.Name);
    }

    private void button2_Click(object sender, EventArgs e)
    {
        // Change Name of Form1 DummyObject
        this.dummyObject.Name = "I am changed from Form1.";
    }

    private void button3_Click(object sender, EventArgs e)
    {
        // Assign new Instance
        this.dummyObject = new DummyObject();

        // Change Name value
        this.dummyObject.Name = "I am rechanged from Form1.";

        // Reassign Form2.DummyObject the newly created instance
        // for synchronization purposes
        this.frm2.DummyObject = this.dummyObject;         
    }       
}

Class which is sharing the object by Property:

public partial class Form2 : Form
{
    private DummyObject dummyObject;

    public Form2()
    {
        InitializeComponent();
    }

    public DummyObject DummyObject
    {
        get { return this.dummyObject; }
        set { this.dummyObject = value; }
    }

    private void button1_Click(object sender, EventArgs e)
    {
        MessageBox.Show(this.dummyObject.Name);
    }

    private void button2_Click(object sender, EventArgs e)
    {
        this.dummyObject.Name = "I am changed from Form2.";            
    }
}

Thankx to every one for their prompt response.

Upvotes: 0

Eric Lippert
Eric Lippert

Reputation: 659956

You've misunderstood what "ref" does. The best way I have to explain what "ref" does is that it makes an alias to a variable. When you say

void M(ref int x)
{
    Console.WriteLine(x);
    x = 10;
}
...
int y = 123;
M(ref y);

what you are saying at the call site is "x is now another name for the variable y". That is, this is exactly as if you'd simply said

int y = 123;
Console.WriteLine(y);
y = 10;

x is an alias for y. It is unfortunate that we chose the word "ref" to mean "make an alias for a variable" because that is confusing, but that's what the language designers chose.

Now if you'd said

void N(int z)
{
    Console.WriteLine(z);
    z = 10;
}
...
int y = 123;
N(y);

that does not make z an alias for y. That code is the same as

int y = 123;
int z = y;
Console.WriteLine(z);
z = 10;

which does not change the value of y, because z and y are two different variables, whereas x and y are two different names for the same variable.

Upvotes: 2

Phil Gilmore
Phil Gilmore

Reputation: 1306

The reason it doesn't do what you want is the first line of Form1.button3_click, creating the second DummyObject instance. This new instance is never sent to Form2, so Form2 only has a copy of the old instance. Now Form1 and Form2 have different objects, hence different messages.

The ref keyword would be used in your example only if the constructor of Form2 wanted to assign a new instance to the parameter on the way OUT (it is different than an out parameter in that it is two-way instead of one-way). Such an assignment would change the value of the Form1.dummyObject field.

Upvotes: 0

Adam Robinson
Adam Robinson

Reputation: 185593

You cannot keep variables synchronized in this manner; there is no concept of ref instance or static variables, only ref parameters. The dummyObject instance variable does (and always will) represent a distinct slot of memory. All you're doing is copying the value from the DummyObject parameter into dummyObject; you're doing nothing that would be affected by whether or not the parameter is being declared as ref.

The typical way is to expose the value of dummyObject as a property on Form2.

public DummyObject DummyObject
{
    get { return dummyObject; }
    set 
    { 
        dummyObject = value;

        // any other code, if any, that might need to execute 
        // when the value is changed
    }
}

But this means that you'll need to hold on to your instance of Form2 so that you can change the value of the property.

Another option, though somewhat convoluted, would be pass a wrapper class that contains that property, rather than adding it to the form.

public class DummyWrapper
{
    public DummyObject DummyObject { get; set; }
}

You then change your forms to use a DummyWrapper instead of a DummyObject, then access the dummyWrapper.DummyObject property when you want to get or set the value. Uas long as you only change the value of the DummyWrapper.DummyObject property and not the actual value of the DummyWrapper, then you'll be pointing at the same instance.

For instance:

public partial class Form2 : Form 
{ 
    private DummyWrapper dummyWrapper = null; 

    public Form2(DummyWrapper dummyWrapper) 
    { 
        InitializeComponent(); 

        this.dummyWrapper = dummyWrapper;
        this.dummyWrapper.DummyObject.Name = "I am Changed"; 
    } 

    private void button2_Click(object sender, EventArgs e) 
    { 
        MessageBox.Show(this.dummyWrapper.DummyObject.Name); 
    } 
} 

Upvotes: 2

Dathan
Dathan

Reputation: 7446

The ref keyword won't give you this capability. Instead, it allows you to re-assign the passed variable to a new instance, but only within the context of the method. To clarify:

void SomeMethodWithRef(ref DummyObject dummy)
{
    dummy = new DummyObject(){Name="Modified"};
}

void CallingMethod()
{
    DummyObject obj = new DummyObject(){Name="Original"};
    SomeMethodWithRef(ref obj);
    // at this point, obj has Name="Modified";
}

However, in your case you're storing the object reference as a field, which has entirely different semantics - reassigning that field is different from reassigning the original variable.

To keep the data synchronized, either operate on the same instance when you make your changes (e.g., this.dummyObject.Name = "I am changed";) instead of creating an entirely new instance, or you'll need to come up with a mechanism for propagating those changes between forms (e.g., have your forms implement INotifyPropertyChanged and subscribe to each other's property change notifications).

Upvotes: 0

Daniel Renshaw
Daniel Renshaw

Reputation: 34177

I think you've misunderstood what the ref keyord does. When you pass the dummyObject into the constructor of Form2, Form2 does not link it's own dummyObject field with the dummyObject field in Form1.

You can keep the data synchronised by avoiding creating new instances of DummyObject or by making Form1 tell Form2 whenever it does create a new instance.

As it stands, you don't actually need to use the ref keyword at all, it won't make any difference if you were to remove it.

Upvotes: 4

Related Questions