C # ref Confusion
I have a confusion that when I pass a refrence variable in the constructor of another class and after passing that refrence object, I recreate the refrence object with a new keyword.
Now the class I passed the overridden object does not reflect the updated data. Below is the problem above:
The object to be passed using Refrence:
public class DummyObject
{
public string Name = "My Name";
public DummyObject()
{ }
}
The class that passes the Refrence value:
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);
}
}
The class to which the 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 have changed" instead of "I have been revised".
How do I sync data?
a source to share
You cannot sync variables this way; there is no concept of ref
instance or static variables, only parameters ref
. An instance variable dummyObject
does (and always will) represent a single memory slot. All you do is copy the value from the parameter dummyObject
to dummyObject
; you are not doing anything that will affect whether the parameter is declared as ref
.
The typical way is to show the value 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 that means you need to hold on to your instance Form2
so that you can change the value of the property.
Another option, albeit somewhat confusing, would be to pass in the wrapper class that contains this property, rather than add it to the form.
public class DummyWrapper
{
public DummyObject DummyObject { get; set; }
}
Then you change your forms to use DummyWrapper
instead dummyObject
, then access the property dummyWrapper.DummyObject
when you want to get or set a value. Uas long, since you are changing the property value dummyWrapper.DummyObject
and not the actual value DummyWrapper
, then you will point to 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);
}
}
a source to share
I think you misunderstood what this key does. When you pass a dummyObject to Form2's constructor, Form2 does not bind its own dummyObject field to the dummyObject field in Form1.
You can keep data in sync by avoiding creating new DummyObject instances, or by making Form1 tell Form2 whenever it creates a new instance.
In reality, you really don't need to use the ref keyword, it won't make any difference if you must remove it.
a source to share
You misunderstood what "ref" does. The best way to explain what "ref" is is that it aliases the variable. When you say
void M(ref int x)
{
Console.WriteLine(x);
x = 10;
}
...
int y = 123;
M(ref y);
what you say at the calling site is "x is now a different name for the variable y". That is, it is exactly as if you just said
int y = 123; Console.WriteLine(y); y = 10;
x is an alias for y. Unfortunately, we chose the word "ref" to mean "make an alias for a variable" because it is confusing, but that's what the language designers chose.
Now if you said
void N(int z)
{
Console.WriteLine(z);
z = 10;
}
...
int y = 123;
N(y);
which doesn't make z an alias for y. This code is the same as
int y = 123;
int z = y;
Console.WriteLine(z);
z = 10;
which does not change the value of y as z and y are two different variables, whereas x and y are two different names for the same variable.
a source to share
The keyword ref
won't give you this opportunity. Instead, it allows you to re-assign a passed variable to a new instance, but only in the context of a 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 are storing the object reference as a field that has completely different semantics - reassigning that field is different from redefining the original variable.
To keep data in sync, either work with the same instance when changes are made (for example this.dummyObject.Name = "I am changed";
) instead of creating a completely new instance, or you will need to create a mechanism to propagate those changes between forms (for example, your forms implement INotifyPropertyChanged
and subscribe to property change notifications each other).
a source to share
The reason it doesn't do what you want is because the first line of Form1.button3_click creates a 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 will only be used in your example if the Form2 constructor wanted to assign a new instance to the OUT path parameter (it differs from the out parameter because it is a two-way path). This assignment will change the value of the Form1.dummyObject field.
a source to share
I revisited my app using a property suggested by Adam Robinson for syncing. Now my code has been modified as shown below and gives the desired results.
The class containing the data to be synchronized:
public class DummyObject
{
public string Name = "My Name is this.";
public DummyObject()
{ }
}
The class that creates a new Inctance and reassigns 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 separating an 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.";
}
}
Thank you everyone for your prompt reply.
a source to share