前段时间发现很多人对参数传递仍然存在很多误区,特在此发个贴,有异意的地方大家一起讨论。参数传递分值传递和引用传递两种,这在书上都有。
通常,在没有显式指出ref和out时都是值传递。说到传值,必须又得说说值类型和引用类型。
值类型存放在堆栈中,直接访问。如果有:int a=0;int b=a;就产生了两个对象。
引用类型需要在堆中显式分配,且不能直接访问,需要在堆栈中分配一个标识对象指向其地址。这个标识对象类似于值类型。
如果:
StringBuilder strb = new StringBuilder();
StringBuilder strb2 = strb;
则在堆中只有一个StringBuilder对象,只是堆栈中有两个标识对象指向它。现在用例子来说明其不同:private void button2_Click(object sender, System.EventArgs e)
{
StringBuilder strb1 = new StringBuilder();
StringBuilder strb2 = new StringBuilder();
Test1(strb1);
Test2(ref strb2);
string str1 = strb1.ToString(); //str1值:"A"
string str2 = strb2.ToString(); //str2值:"BC"
}void Test1(StringBuilder strb)
{
//strb和strb1是堆栈中的两个标识对象,但指向相同的地址,这个操作是改变堆中的对象。
strb.Append("A"); //这里将strb指向一个新的堆中对象地址,所以后面的操作与strb1无关。这个新对象随着strb在堆栈中的消失最终成为垃圾对象
strb = new StringBuilder("B");
strb.Append("C");
}void Test2(ref StringBuilder strb)
{
//这里的strb和strb2在堆栈中的地址是一样,即他们在堆栈中也是同一个标识对象。
//那么不管对strb如何操作,同样都会反应到str2中。
strb = new StringBuilder("B");
strb.Append("C");
}值传递:传的是对象的值拷贝。(引用类型和值类型看上去不同,实质上一样,只是引用类型是拷贝堆栈中的标识对象,所以就是:两个标识对象,指向同一堆中的对象)
引用传递:传的是地址,即对象与函数参数对象完完全全是同一对象。(这里的对象都是指的堆栈中的对象,当然,堆栈中的标识对象是同一个,那么指向的对象就更是同一个,呵)
[Java]中没有引用传递。
[共享1]try{}finally{}中的return顺序问题:
http://community.csdn.net/Expert/topic/3990/3990402.xml
通常,在没有显式指出ref和out时都是值传递。说到传值,必须又得说说值类型和引用类型。
值类型存放在堆栈中,直接访问。如果有:int a=0;int b=a;就产生了两个对象。
引用类型需要在堆中显式分配,且不能直接访问,需要在堆栈中分配一个标识对象指向其地址。这个标识对象类似于值类型。
如果:
StringBuilder strb = new StringBuilder();
StringBuilder strb2 = strb;
则在堆中只有一个StringBuilder对象,只是堆栈中有两个标识对象指向它。现在用例子来说明其不同:private void button2_Click(object sender, System.EventArgs e)
{
StringBuilder strb1 = new StringBuilder();
StringBuilder strb2 = new StringBuilder();
Test1(strb1);
Test2(ref strb2);
string str1 = strb1.ToString(); //str1值:"A"
string str2 = strb2.ToString(); //str2值:"BC"
}void Test1(StringBuilder strb)
{
//strb和strb1是堆栈中的两个标识对象,但指向相同的地址,这个操作是改变堆中的对象。
strb.Append("A"); //这里将strb指向一个新的堆中对象地址,所以后面的操作与strb1无关。这个新对象随着strb在堆栈中的消失最终成为垃圾对象
strb = new StringBuilder("B");
strb.Append("C");
}void Test2(ref StringBuilder strb)
{
//这里的strb和strb2在堆栈中的地址是一样,即他们在堆栈中也是同一个标识对象。
//那么不管对strb如何操作,同样都会反应到str2中。
strb = new StringBuilder("B");
strb.Append("C");
}值传递:传的是对象的值拷贝。(引用类型和值类型看上去不同,实质上一样,只是引用类型是拷贝堆栈中的标识对象,所以就是:两个标识对象,指向同一堆中的对象)
引用传递:传的是地址,即对象与函数参数对象完完全全是同一对象。(这里的对象都是指的堆栈中的对象,当然,堆栈中的标识对象是同一个,那么指向的对象就更是同一个,呵)
[Java]中没有引用传递。
[共享1]try{}finally{}中的return顺序问题:
http://community.csdn.net/Expert/topic/3990/3990402.xml
解决方案 »
- 【高手进】求助webbrowser的一个异常!非常奇怪
- 如何获取txt文档内容的font字体属性
- 未能加载文件或程序集“CrystalDecisions.Web”或它的某一个依赖项。系统找不到指定的文件
- 如何获取存储过程Return 的值
- VS中窗体数据传递的问题
- 如何让一个程序后台运行?
- Winform中 Chart 折线图表示 怎样实现标尺(游标)功能
- 怎样在DATASET中倒入符合格式的文本文件数据?
- 在vs,net中创建用户控件和组件有什么区别?
- SOSSOSOSOSOSOSOSOSOSOS
- jmail收邮件如果何不重复收取,只收新邮件
- ???为什么做的安装程序,安装后生成的快捷方式有问题???
1.入门C#时经常看到这样的描述:.NET中的String都是Unicode编码。
在入门之后没太看这样的基础书并且多接触一些编码问题后,我的潜意识总觉得String有很多种编码,utf8,unicode,ascii等,并且不认为C#中有gb2312编码。
2.System.Text.Encoding.Default似乎可以解决一切编码,因为我每次用Default.GetString()来读取流中的字符串都成功!所以Default应该是根据字节的编码方式而改变的,比如如果你的字节序是ascii编码,那么Default就是ascii编码。只到前几天在CSDN的Java社区看到一个编码问题,外加自己的几个小时的实验,终于对编码问题理清了头绪。简短描述:
.NET中的String确实只有Unicode一种。所以编码格式的字节序列转换成String时最终都是以Unicode表示。转换成String后它以后的编码格式已经不重要或者说没有意义了。
System.Text.Encoding.Default是取系统的当前ANSI代码页的编码(MSDN上抄的),即当前系统的编码。(在我们的机子上一般都是"gb2312")这就是我每次用Default读取文件流都正确,且必须用Default读取才正确的原因----其实用Encoding.GetEncoding("GB2312")也一样。详细介绍:
在每次进行byte[]-->String(other-->Unicode)和String-->byte[](Unicode-->other)时都会有编码转换。
比如通常的转换都有设置编码的地方,如StreamReader(string path [, System.Text.Encoding encoding]),Response.Charset,这就相当于你告诉系统byte[]是什么编码,这时候.NET用你指定的编码方式去解码,然后转换成Unicode编码方式的String.
也就是说,不管何时,我们所指定的编码都只是指byte[]。
即Encoding.UTF8.GetString(byte[] buffer)是告诉系统buffer的编码是UTF8。
byte[] buf = Encoding.UTF8.GetBytes(string str)是告诉系统返回的buf编码方式是UTF8。你可能告诉系统一个假的编码方式,或者你没有告诉系统并且byte[]的编码不是用的默认编码,那么系统解码仍然会用指定编码方式进行,在机器看来他仍然解码成功,然后转换成Unicode编码,因为机器只知道0,1字节序,他不知道解码出来的东西是否是混乱的,在他看来一切正常。
但我们去看,就会发现字符串成了一些莫名其妙的符号而没有任何意义,这就是所谓的乱码。
就好比:"you yi ge",本来是拼英"有一个",你却偏偏告诉别人这是英语,别人用英语去拼,就不知道是怎么回事了,就成了乱码,呵呵。
即:字节序是按指定编码方式编码,它有一个特定的编码方式,但它本身是中性的,不含有任何编码信息。编码方式理论上是独立于语言的,但实际上需要语言去支持。如JAVA中有"GBK"(gb2312扩展)编码,但.NET中没有。你用Encoding.GetEncoding("GBK")会抛异常。
ref要求变量必须在传递之前赋值,所以如下语句是错误的:int i;
FunctionA( ref i );
out不要求变量在传递之前赋值,但对接收变量的函数进行了约束,要求在该函数内必须给变量赋值。
简而言之就是,如果编译器在函数声明中看到了ref,则认为这个变量是已经被赋了初值的,而如果在声明中看到了out,则认为这个变量没有被赋初值,而不论其是否在前面已被赋初值。如:void FunctionA( out int i )
{
int j = i;//错误,编译器会说i没有被赋初值。
}除此之外,标明为out的参数必须在函数体内部进行赋值,并且是所有的流程途径都必须有明确的赋值。