飘遥的Blog

C/C++/.NET
  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

.NET 中的引用类型 string

Posted on 2007-12-15 19:04  Zzx飘遥  阅读(612)  评论(0编辑  收藏  举报
String 在.net 2.0 中的定义为:
[SerializableAttribute]
[ComVisibleAttribute(true)]
public sealed class String : IComparable, ICloneable, IConvertible,
    IComparable<string>, IEnumerable<string>, IEnumerableIEquatable<string>

毫无疑问,string为引用类型,但在使用过程中它又表现出一些值类型的特点。
1.string 重载了 ==、!= 运算符 

//重载== 运算符
public static bool operator ==(String a, String b)
{
    return Equals(a, b);
}
 
//重载!= 运算符
public static bool operator !=(String a, String b)
{
    return !Equals(a, b);
}

string 对象重写了 Equals 方法,实现字符串的比较。

2.string 是只读的。
不能修改该对象实例的值,实际操作中对该对象实例的修改返回的是该对象的新的实例。而 StringBuilder 则是在原对象实例基础上的修改,这就是修改操作时 StringBuilder 效率高于 string 对象的原因。string 对象保留在堆上,而不是堆栈上,当相同的字符串赋值到两个string变量时,会得到相同内存中的字符串的两个引用,这样做的目的是提高效率,对其进行了特殊优化,字符串是经常用的基本数据类型并且是只读类型,没有必要把相同的字符串在内存中保留多个复本。

//
相同的字符串赋值到两个string变量时,会得到相同对内存中的字符串的两个引用
string aa = "hello";
string bb = "hello";
Console.Write(string.Equals(aa, bb)); //true
Console.Write(string.ReferenceEquals(aa, bb)); //true
 
//改变字符串,获得新的实例
bb += "o";
Console.Write(string.Equals(aa, bb)); //false
Console.Write(string.ReferenceEquals(aa, bb)); //false

3.参数传递中的假象 
疑问:当字符串变量作为参数传递时并未改变它的值。

string
str = "hello";
Console.WriteLine(str); //hello
Console.WriteLine(ChangeString(str)); //helloo
Console.WriteLine(str); //hello
 
Console.WriteLine(string.Equals(str, str)); //true
Console.WriteLine(string.Equals(str, ChangeString(str))); //false
 
//改变字符串
private string ChangeString(string str)
{
    str += "o";
 
    return str;
}

原因是字符串是只读的,改变时创建了一个新的对象。这时应该明确的标识 ref 或 out。
这不是个别现象,引用类型作为参数传递欲改变对象本身时都应明确的标识 ref 或 out,这让我想起当初学C语言是指针作为参数传递时为什么没有改变原指针本身:应该传递的是指针的地址。
下面的代码举例比较明显:

//测试
Test1 tst = new Test1();
tst.aa = 1;
 
ChangeClass(tst);
Console.WriteLine(tst.aa); //1
 
ChangeClassRef(ref tst);   
Console.WriteLine(tst.aa); //3
 
//测试值传递参数
public void ChangeClass(Test1 tst)
{
    tst = new Test1();
    tst.aa = 2;
}
 
//测试引用传递参数
public void ChangeClassRef(ref Test1 tst)
{
    tst = new Test1();
    tst.aa = 3;
}
 
//测试用类
public class Test1
{
    public int aa = 0;
}