原文请见: http://blog.csdn.net/zhzuo/archive/2004/04/05/22027.aspx
本文讨论原文的几个技术细节。
对于作者所写的从 form2 传值到 form1 的实现中所用的方法:
public Form2(TextBox heckbo,CheckBox heckbox)
{
InitializeComponent();
this.textBoxFrm2.Text = heckbo.Text;
this.checkBoxFrm2.Checked = heckbox.Checked;
this.textBoxFrm12 = heckbo;
this.checkBoxFrm12 = heckbox;
}
private void buttonOK_Click(object sender, System.EventArgs e)
{
this.textBoxFrm12.Text = this.textBoxFrm2.Text;
this.checkBoxFrm12.Checked = this.checkBoxFrm2.Checked;
this.Close();
}
其中作者没有写到对 form1 的修改。由 form2 的构造函数可知,此函数引入了声明了两个形参, heckbo 和 heckbox ,那么对于调用构造函数的 form1 ,对应的按钮点击事件则应写为:
private void buttonEdit_Click(object sender, System.EventArgs e)
{
Form2 formChild = new Form2(this.textBoxFrm1,this.checkBoxFrm1);
formChild.Show();
}
下面来解释此方法的实现细节:
在 c# 中值被分为两种型别,分别是 value 型别和 reference 型别,其中 int,float 等型别被划分为 Value 型别,而数组等型别则被划分为 reference 型别,那么 value 型别和 reference 型别有什么区别呢? 对于 value 型别,当你用一个 value 型别的变量为另外一个 value 型别的变量赋值时,执行了深拷贝,两个变量同时拥有自己的变量值,修改其中一个变量的值对另外一个变量的值没有影响,如:
string a=”abc”;
string b=a;
string a=”cde”;
console.writeline(a);
console.writeline(b);
输出为: cde
abc
然而对于 reference 型别就完全不是这样了,当我们建立一个 reference 型别的变量(如作者程序中的数组)的时候,系统会在受控堆( managed heap )上划分一块区域用以储存这个变量的值,而我们声明的变量名则只保存了那块区域的地址。那么当我们在用一个 reference 变量为另外一个 reference 变量赋值的时候发生了什么呢?被赋值的变量只保存了赋给它值的那个变量的地址,所以两个变量拥有了同一个地址,指向了同一个储存区域。这时,无论改变哪一个变量的值,都会影响另外一个变量的值,这也是作者所用来从 form2 向 form1 传值的方法!
在作者的程序中, form2 的构造函数接受一个 TextBox 的形参和一个 CheckBox 的形参,而这两个形参都属于 reference 型别(一般用 new 创建出来的 object 都属于 reference 型别 , 不过也不绝对)当我们调用构造函数时,实参 TextBoxfrm1 和 CheckBoxfrm1 被传递给函数,而函数的参数只在函数内部有效,所以又创建了两个临时的 object 用以传递参数:
private TextBox textBoxFrm12;
private CheckBox checkBoxFrm12;
接着这两个 object 被形参赋值:
this.textBoxFrm12 = heckbo;
this.checkBoxFrm12 = heckbox;
此时的 textBoxFrm12 和 checkBoxFrm12 分别持有 TextBoxfrm1 和 checkBoxfrm1 的地址,接下来在 button_click() 事件中,将 textBoxFrm12 和 checkBoxFrm12 的值更改:
this.textBoxFrm12.Text = this.textBoxFrm2.Text;
this.checkBoxFrm12.Checked = this.checkBoxFrm2.Checked;
根据上面提到的 reference 型别的特点,对持有相同地址的两个 object 中的一个的内容进行更改将影响另外一个 object 。对 textBoxFrm12 和 checkBoxFrm12 的内容的更改,同时也对 TextBoxfrm1 和 checkBoxfrm1 的内容进行了更改,从而将 form2 的值传递给了 form1 。
那么为什么不直接用 string 字串来传送 TextBox 的值呢?如以下程序:
private string n
public Form2(string s)
{
InitializeComponent();
this.textBoxFrm2.Text =s
n=s;
}
private void buttonOK_Click(object sender, System.EventArgs e)
{
n = this.textBoxFrm2.Text;
this.Close();
}
由前述可知当我们把一个 string 变量赋给另外一个 string 变量时,实际上产生了两个含有相同值的独立 string 变量,当把实参赋给形参 s 时, s 为一个独立于实参的变量,改变 s 的值不会改变实参的值,同样对于 n=s, 改变 n 的值一样不会改变 s 的值。
那么就没有办法用字符串的方法传值么?看下面程序
Form1 做如下更改:
private void form1button_Click(object sender, System.EventArgs e)
{
string m=TextBoxfrm1.Text;
Form2 frm2=new Form2(ref m);
frm2.Show();
TextBoxfrm1.Text=m;
}
Form2 做如下更改:
public Form2(ref string s)
{
InitializeComponent();
s=TextBoxfrm2.Text;
}
将 form2 的 button_click() 事件中除了 this.close(); 语句的其他语句删除。
运行此程序可以将 TextBoxfrm2 文本框中的初值传递给 form1 中的 TextBoxfrm1 。其中原因是使用了传址参数 ref ,此关键字允许为传入的实参设置一个别名,而此别名和实参同时指向同一个值。需要注意的是在调用函数的时候亦必须加上传址参数 ref 。但此方法也有其不完善的地方,它只能将 TextBoxfrm1 的值设为 form2 调用时 TextBoxfrm2 的初值,而对 TextBoxfrm2 值的任何改动,在 TextBoxfrm1 中都无法体现出来,原因在于 ref 所定义的参数 s 只在函数体内可见,如果要使它能够相应 button_click() 事件,则必须定义一个临时字串 m=s, 然后令 m=TextBoxfrm2.Text, 但是这样又等于定义了两个独立的变量,对 m 的改动不会反映到 s 上,也就不会反映到 TextBoxfrm1.Text 上。
如果你有什么好的解决方法,欢迎与我联系: [email protected]