您的位置:首页 > 编程语言 > C#

C#基础知识点总结

2010-12-25 09:26 344 查看
  最近重新复习了一个c#基础知识,在测试StringBuilder与字符串连接的比较时,没想到二者的差距竟然如此之大,用StringBuilder连接字符50000次竟然是0毫秒,而用字符串连接为1750毫秒。当连接500000次的结果差距更不用说了,下面总结一下学习c#的一些知识点:

1.StringBuilder与字符串连接比较

1    Console.WriteLine("String routine");

2 string a = "a";

3 string str = string.Empty;

4 int istart, istop;

5 istart = Environment.TickCount & Int32.MaxValue;

6 Console.WriteLine("Start: " + istart);

7 for (int i = 0; i < 50000; i++)

8 {

9 str += a;

}

istop = Environment.TickCount;

Console.WriteLine("Stop: " + Environment.TickCount);

Console.WriteLine("Difference: " + (istop - istart));

Console.WriteLine("StringBuilder routine");

StringBuilder builder = new StringBuilder();

istart = Environment.TickCount & Int32.MaxValue;

Console.WriteLine("Start: " + istart);

for (int i = 0; i < 50000; i++)

{

builder.Append(a);

}

istop = Environment.TickCount;

str = builder.ToString();

Console.WriteLine("Stop: " + Environment.TickCount);

Console.WriteLine("Difference: " + (istop - istart));

Console.Read();

  执行结果却大吃一惊,知道用字符串拼接速度慢,但没想到会慢到如此地步,下图是拼接50000个字符:

    


  当拼接500000个字符时,执行结果为:

    


  出现这个结果的原因是:第一是字符串是不可变的,每次字符串变量的内容发生改变时,都必须重新分配内存。例如上面迭代50000次的循环,每次迭代都将一个字符连接到字符串,这样,内存中最终将有50000个字符串,每个字符串与其前面的字符串想比只差1个字符,第二是StringBuilder类是通过分配一个工作区解决这个问题,并在这个工作区中可以对字符串进行追加、插入、删除、移除和替换等操作。也就是说所有的操作都在一个缓存中进行,不需要任何内存分配,所以速度还是明显不一样。。。

2. 深拷贝和浅拷贝

1 test mytest = new test("Joanna");

2 mytest.Age = 36;

3 test clone1 = (test)mytest.Clone(); //浅拷贝

4 test clone2 = mytest; //深拷贝

5 Console.WriteLine(Object.ReferenceEquals(mytest.Name, clone1.Name)); //true

6 Console.WriteLine(Object.ReferenceEquals(mytest.Name, clone2.Name)); //true

7 Console.WriteLine(Object.ReferenceEquals(mytest.Age, clone1.Age)); //false

8 mytest.Name = "Julie";

9 Console.WriteLine(Object.ReferenceEquals(mytest.Name, clone1.Name)); //false

Console.WriteLine(Object.ReferenceEquals(mytest.Name, clone2.Name)); //true

Console.WriteLine(Object.ReferenceEquals(mytest.Age, clone2.Age)); //false

Console.Read();

类代码如下:

13 public class test : ICloneable

14 {

15 public int Age;

16 public String Name;

17 public test(string myname)

18 {

19 Name = myname;

20 }

21 public object Clone()
22 {
23 return MemberwiseClone();
24 }

25 }

从上面代码中我们可以看出如下几点:

(1)当字段为引用类型时,不是深拷贝还是浅拷贝,指针都指向同一个地址,如上面代码中的5和6的比较。

(2)当字段为值类型时,不管是浅拷贝还是深拷贝,指针指向都为不同的地址,如上面代码中的9和11的比较。 (3)当字符串不同时,浅拷贝指向的指针和原来的指针不同,如“9”,深拷贝指向的还是为同一个地址如“11”

出现这种情况的原因如下:

(1) 浅拷贝创建原对象类型的一个新实例,然后将原对象的非静态字段复制到新对象。对于引用类型字段,则只复制指向该值的指针。因些,拷贝的对象和原对象指向相同的引用对象。

(2)深拷贝是复制所有字段,它会创建引用对象的副本,并在副本中提供这些对象的引用。

(3)CLR还在内存中预留了拘留池,是为了避免存储重复的字符串值。在为字符串变量赋值时,先检查字符串值在拘留池中是否存在指向该字符串的指针,如果存在,则把指针指向已有的对象,如果不存在,则另开辟一块内存,用来存储字符串,将指针指向该内存地址,并将拘留池中的指针也指向该内存地址。这也是为什么字符串不同时,浅拷贝与深拷贝的指向的地址也会不同。

3.值类型和引用类型:

(1)内存分配:引用类型分配到堆中,而值类型分配到线程栈或调用栈中。创建引用类型时,会初始化为null,表示它不指向任何数据,值类型则初始化为0.

(2)内存释放:变量超出其作用域时,会释放栈中的内存,而堆内存达到系统内存的下限阈值时,会启动垃圾回收机制,释放堆中内存。

(3)变量赋值:变量设置为引用类型时,它会接收指向原对象的一个指针,而不是对象值本身,变量设置为值类型时,会逐字段地复制原变量,并赋给新变量。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: