当前位置:编程学习 > asp >>

.Net 框架程序

1 认识string
     字符串是我们编程中使用最多的类型之一,在C#语言中它作为基元类型。从继承性上来说,string直接继承自object,它是一个引用类型,总是分配在托管堆中,但是它的行为表现的却有着值类型的特性,比如它可以不用new去构建对象,而可以直接赋值的方式;作为函数的引用类型参数,在函数内的操作不会影响到形参等等。
 
[csharp]  
class Program  
 {  
        static void Main(string[] args)  
        {  
             public string s = "hello";  
             Printing (s);  
             Console.WriteLine(s);  
         }     
  
}  
  
public static void Printing(string ss)  
{  
      ss = "hello world";  
      Console.WriteLine(ss);  
}  
 
 
 
     在上面的代码中声明了一个字符串变量s,对变量直接进行了赋值s = "hello",而没有使用创建引用类型的方式s= new string("hello"),我们用ILDasm.exe去查看生成的IL代码,会发现在创建引用类型对象时使用的newobj并没有出现,取而代之的是一个新指令ldstr,它从元数据中获取一个文本常量来构建一个string对象,CLR通过这种方式来优化对string类型的操作。紧接着Printing函数会被调用,它接收一个string对象,按照我们对引用类型变量的理解,Printing函数在内部对string对象的修改会影响外部的string对象,但运行结果并没有像我们想的那样,外部的对象并没有发生变化,而这正好印证了上面所说的string通过特殊的语法去创建对象。在调用Printing函数时如下示意图所示:在Printing函数内部发生了如下的变化:
 
 
 
通过对上面的示意图我们不难理解函数的输出。
 
 
 
2 字符串恒定性
      字符串是恒定的,在创建后就不会在变化,这是string一个很重要的特性。考虑如下代码:    
 
              string s ="hello world";
 
               Console.WriteLine(s.ToUpper().Substring(1,2));
 
               Console.WriteLine(s);
 
在输出的第一行我们对字符串做了一些操作,但是这些操作并没有更改s的值,在第二行的输出中仍然是hello world。在对s的操作中,每次的操作都会创建一个新的string对象,原有的s并没有改变,这就是字符串的恒定性。
 
        这个特性为string类型带来了一些好处同时也带来了一些性能上的损失,好处是在不用锁定的情况下就可以在多个线程间操作而不用同步;坏处是对字符串的操作产生了大量的临时对象,这些对象会加剧垃圾收集器的收集工作,对性能有一定的影响。
 
3 字符串的驻留
    因为字符串的恒定性,在作为函数参数或其他一些拷贝操作时都会产生一个全新的副本,这对内存是一个极大的浪费;同时字符串的比较也是一个费时的操作,它要比较字符串中对应位置的每一个字符。为了解决上述的问题,CLR在内部维护一个哈希表,将字符串作为键,将该字符串在托管堆中的引用作为值。当创建一个字符串的时候,CLR会首先在这个哈希表中去查找对应的键是否存在,如果不存在,就创建一个该字符串的副本,把该副本存储在哈希表中,并返回一个该副本的引用;如果存在和创建的字符串相同的键,则直接返回该键对应的值(字符串的引用)。
 
保存在哈希表中的字符串不受垃圾收集器的管理,也就是说只有在程序域被卸载的时候,这个哈希表才会被释放。
 
对动态创建的字符串,CLR并没有选择留用,我们可以用string的静态方法Intern来实现强制的留用。如下的代码:
 
[csharp]  
string s1 = "hello";  
 string s2 = "hello";  
 bool b = object.ReferenceEquals(s1, s2);  
 Console.WriteLine("s1和s2是否具有相同的引用:"+b);  
 string s3 = "hello world";  
 string s4 = s1 + " world";  
 bool b1 = object.ReferenceEquals(s3, s4);  
 Console.WriteLine("s3和s4是否具有相同的引用:" + b1);  
 Console.WriteLine("s3和s4是否具有相同的值:" + s3.Equals(s4));  
 string s5 = string.Intern(s4);  
 b1 = object.ReferenceEquals(s3, s5);  
 Console.WriteLine("s3和s5是否具有相同的引用:" + b1);  
 
 
 
输出如下: 
 
1和s2是否具有相同的引用:True
 
s3和s4是否具有相同的引用:False
 
s3和s4是否具有相同的值:True
 
s3和s5是否具有相同的引用:True
 
 4  字符串池
编译源代码时,文本常量会被嵌入到元数据中,这样就会导致相同的字符串会被多次的嵌入到元数据中,增大了生成模块的容量。为了解决这个问题,C#编译器把字符串写入一次后,在后面的代码中出现相同的,则只是对写入字符串的一个引用,有效保证了生成模块的容量,这就是字符串池技术。
补充:Web开发 , ASP.Net ,
CopyRight © 2012 站长网 编程知识问答 www.zzzyk.com All Rights Reserved
部份技术文章来自网络,