在看anytao的《你必须知道的.NET》 http://www.cnblogs.com/anytao/archive/2008/08/27/must_net_22.html,看到字符串驻留这部分时,对于里面提到的几个问题有些小疑问,特别是后面几个问题,没看懂,所以特地做了些小测试,也不知是否正确,或者说那里表达得有问题,请了解这方面的大侠们多指点。
该说的在代码里已经说,其他的就不废话了
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 6 namespace Test 7 { 8 9 10 class Program 11 { 12 const string strConst = "strConst";//编译时确定,存放在元数据里,被访问之前不会被加载到内存 13 readonly static string strStatic = "strStatic";//运行时确定 14 15 static void Main(string[] args) 16 { 17 string s0 = "str"; 18 19 //下面这个测试说明了:两个字符串动态“相加”后得到的字符串是在运行时去确定的,不会添加到字符串池里 20 #region 测试动态生成的string 21 22 string s1 = s0 + "Test";//s2由两个字符串动态“相加”得到,由IL代码可知是调用 string String::Concat(string, string)方法后取返回值得到 23 Console.WriteLine("s1 is (test Concat): " + string.IsInterned(s1)); 24 25 #endregion 26 27 28 //下面这个测试说明了:如果const string 没有被访问,那么就不会被添加到字符串池里 29 #region 测试 const string 30 31 //执行下面这句代码时,编译器会直接把字符串 "strConst" 嵌入到代码来替代 常量strConst, 32 //这样子就会导致将字符串 "strConst" 加入到字符串池里(如果字符串池没有这个项)。所以这样子测试是不准确的 33 // Console.WriteLine(string.IsInterned(strConst)); 34 35 //const string 在编译时嵌入到代码替换对应的那个常量;当const string 所在的方法被调用时,该const string就被添加到字符串池里 36 37 string s2 = s0 + "Const"; 38 Console.WriteLine("s2 is (test const string): " + string.IsInterned(s2)); 39 //Console.WriteLine(strConst); 40 //Console.WriteLine("s4 is: " + string.IsInterned(s4)); 41 42 #endregion 43 44 45 //下面这个测试说明了:static string 在类型任一个成员被访问之前就已经被添加到字符串池里了 46 #region 测试static string 47 48 //static string,在这个类型的任何一个成员被访问之前,CLR会调动类型的类型构造器,也就是静态构造器(可显式定义,但只能有一个,必须无参) 49 //类型构造器先调用static成员的初始化代码,再调用自己显式添加的代码。所以static string初始化时赋予的字符串会被添加到字符串池 50 51 string s3 = s0 + "Static"; 52 Console.WriteLine("s3 is (test static string): " + string.IsInterned(s3)); 53 54 #endregion 55 56 57 //下面这个测试说明了:字符串不在乎声明得前面还是后面,因为字符串常量是在编译时确定的, 58 //反正在方法被访问时,方法就被加载到内存,里面所有的字符串常量一次性全部添加到字符串池里 59 #region 测试先输出后定义 60 61 // string s7 = strConst;//在编译的时候直接用常量strConst的内容 "strConst" 嵌入代码替代 s7;从而添加进了字符串池 62 63 string s4 = s0 + "before define"; 64 Console.WriteLine("s4 is (test before define): " + string.IsInterned(s4)); 65 66 //在编译的时候就已经把 "strbefore define" 放到字符串池里了。如果是放在其他函数里,为什么不也在编译的时候就放到字符串池里? 67 string s40 = "strbefore define"; 68 69 #endregion 70 71 72 //下面这个测试说明了:方法被调用前,里面所有的东西都只是在元数据里,没有被加载到内存; 73 //当某方法被调用时才会被加载到内存,方法的所有文本字符串一次性添加到字符串池里 74 #region 调用方法 75 76 string s5 = s0 + "Change"; 77 Console.WriteLine("s5 is (before mothed): " + string.IsInterned(s5));//调用方法前,"strChange" 没有被添加到字符串池里 78 StrChange(); 79 Console.WriteLine("s5 is (after mothed) : " + string.IsInterned(s5));//调用方法后,"strChange" 已经被添加到字符串池里了 80 81 82 #endregion 83 84 Console.ReadKey(); 85 } 86 87 88 //方法里的字符串常量在编译时就会嵌入到代码里 89 //方法被调用之前只是以IL代码的形式存放在元数据里,没有被加载到内存里;当方法被调用时才会被加载到内存,方法里的所有文本字符串常量就全部添加到字符串池里 90 static string StrChange() 91 { 92 return "strChange"; 93 } 94 } 95 96 }