C#参考混淆

C#参考混淆,c#,C#,我有一个困惑,当我在另一个类的构造函数中通过引用传递变量,并且在通过引用传递该对象之后,我用new关键字重新创建引用对象 现在,我传递引用对象的类没有反映更新的数据。 上述问题的示例如下所示: 要通过引用传递的对象: 通过引用的类: 通过引用向其传递对象的类: 当我在表格1中重新分配对象并在表格2中显示其值时,它仍然显示“我已更改”而不是“我已重新更改” 如何保持数据同步?不能以这种方式保持变量同步;没有ref实例或静态变量的概念,只有ref参数。dummyObject实例变量确实(并且始终)表

我有一个困惑,当我在另一个类的构造函数中通过引用传递变量,并且在通过引用传递该对象之后,我用new关键字重新创建引用对象

现在,我传递引用对象的类没有反映更新的数据。 上述问题的示例如下所示:

要通过引用传递的对象: 通过引用的类: 通过引用向其传递对象的类: 当我在表格1中重新分配对象并在表格2中显示其值时,它仍然显示“我已更改”而不是“我已重新更改”


如何保持数据同步?

不能以这种方式保持变量同步;没有
ref
实例或静态变量的概念,只有
ref
参数。
dummyObject
实例变量确实(并且始终)表示一个不同的内存插槽。您所做的只是将值从
DummyObject
参数复制到
DummyObject
;您所做的任何操作都不会受到参数是否声明为
ref
的影响

典型的方法是将
dummyObject
的值作为
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
    }
}
但这意味着您需要保留
Form2
的实例,以便更改属性的值

另一个选项,虽然有点复杂,但将传递包含该属性的包装器类,而不是将其添加到表单中

public class DummyWrapper
{
    public DummyObject DummyObject { get; set; }
}
然后将表单更改为使用
DummyWrapper
而不是
DummyObject
,然后在需要获取或设置值时访问
DummyWrapper.DummyObject
属性。Uas只要您只更改
DummyWrapper.DummyObject
属性的值,而不是
DummyWrapper
的实际值,那么您将指向同一实例

例如:

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); 
    } 
} 

我想你误解了裁判的作用。将dummyObject传递到Form2的构造函数时,Form2不会将其自己的dummyObject字段与Form1中的dummyObject字段链接

您可以通过避免创建DummyObject的新实例或使Form1在创建新实例时告诉Form2来保持数据同步


就目前情况而言,实际上根本不需要使用ref关键字,如果要删除它,也不会有任何区别。

ref关键字不会为您提供此功能。相反,它允许您将传递的变量重新分配给新实例,但只能在方法的上下文中。澄清:

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";
}
但是,在您的例子中,您将对象引用存储为一个字段,该字段具有完全不同的语义-重新分配该字段与重新分配原始变量不同


要保持数据同步,请在进行更改时对同一实例进行操作(例如,
this.dummyObject.Name=“I am change”;
),而不是创建一个全新的实例,或者您需要提出一种在表单之间传播这些更改的机制(例如,让您的表单实现
INotifyPropertyChanged
,并订阅彼此的属性更改通知).

它不执行您想要的操作的原因是Form1的第一行。按钮3\u单击,创建第二个DummyObject实例。此新实例从未发送到Form2,因此Form2只有旧实例的副本。现在Form1和Form2具有不同的对象,因此消息也不同

仅当Form2的构造函数希望为OUT上的参数分配一个新实例时,才会在示例中使用ref关键字(它与OUT参数不同,因为它是双向的,而不是单向的)。这样的分配会更改Form1.dummyObject字段的值。

您误解了什么是“ref”是的。我要解释“ref”的作用的最好方法是,它为一个变量生成了一个别名

void M(ref int x)
{
    Console.WriteLine(x);
    x = 10;
}
...
int y = 123;
M(ref y);
您在调用站点所说的是“x现在是变量y的另一个名称”。也就是说,这与您刚才所说的完全一样

int y = 123;
Console.WriteLine(y);
y = 10;
x是y的别名。不幸的是,我们选择了“ref”这个词来表示“为变量生成别名”,因为这很容易混淆,但这正是语言设计者所选择的

现在如果你说

void N(int z)
{
    Console.WriteLine(z);
    z = 10;
}
...
int y = 123;
N(y);
这不会使z成为y的别名。该代码与

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

这不会改变y的值,因为z和y是两个不同的变量,而x和y是同一个变量的两个不同名称。

我重新考虑了我的应用程序,使用Adam Robinson建议的属性进行同步。现在,我的代码已更改,如下所示,并产生了所需的结果

类,该类包含需要同步的数据: 类创建新实例并将其重新指定给属性: 按属性共享对象的类: 感谢所有人的及时回复

int y = 123;
Console.WriteLine(y);
y = 10;
void N(int z)
{
    Console.WriteLine(z);
    z = 10;
}
...
int y = 123;
N(y);
int y = 123;
int z = y;
Console.WriteLine(z);
z = 10;
public class DummyObject
{
    public string Name = "My Name is this.";        

    public DummyObject()
    { }        
}
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;         
    }       
}
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.";            
    }
}