String类的Format重载方法,用来格式化需要的字符串非常方便。常用的重载方法原型有:
Format(String, Object)
Format(String, Object, Object)
Format(String, Object, Object, Object)
Format(String, Object[])
它们都调用了另外一个重载方法:
Format(IFormatProvider, String, Object[])
在这个方法中,调用了System.Text.StringBuilder类中的AppendFormat方法:
AppendFormat(IFormatProvider, String, Object[])
在这个方法内部对字符串进行了解析,包括我们常常利用大括号”{}”对来匹配变量参数,如:
String.Format(”this is {0}”, UserName);
不知道大家有没有在这个format参数中误用大括号的经历,比如参数本身是段脚本语句,需要使用到大括号,如:
String.Format(”return 1;} function Method{0}(){”, id);
这段代码会抛出FormatException的异常。我们察看Reflector,看看当AppendFormat方法解析这个 “return 1;} function Method{0}(){” 字符串时候,会发生什么情况:
switch (ch1) {
case ‘}’:
if ((num1 < num2) && (chArray1[num1] == ‘}’))
{ num1++; }
else { StringBuilder.FormatError(); }
break;
大概在24行开始,开始判断是否是“}”字符,如果在其后没有紧跟另一个“}”符号,程序立即会抛出异常(通过StringBuilder的FormatError方法)。所以能够解释我们上面所举例子中的情况。但是根据这个反编译的源代码,就不能解释很多正常的情况,比如:
String.Format(”this is {0}”, UserName);
仔细跟踪这个AppendFormat方法,发现都会出现第49行一个数组的调用超出边界,将抛出System.IndexOutOfRangeException:
chArray1[num4++] = ch1;
不知何故,此方法在Framework中能顺利运行,难道是Reflector反编译有误?
以下为反编译的AppendFormat方法代码(真佩服写FCL的牛人,代码逻辑真是深奥阿 ):
AppendFormat
1public StringBuilder AppendFormat(IFormatProvider provider, string format, params object[] args)
2{
3 int num3;
4 if ((format == null) || (args == null))
5 {
6 throw new ArgumentNullException((format == null) ? "format" : "args");
7 }
8 char[] chArray1 = format.ToCharArray(0, format.Length);
9 int num1 = 0;
10 int num2 = chArray1.Length;
11 char ch1 = '\0';
12 ICustomFormatter formatter1 = null;
13 if (provider != null)
14 {
15 formatter1 = (ICustomFormatter) provider.GetFormat(typeof(ICustomFormatter));
16 }
17Label_004E:
18 num3 = num1;
19 int num4 = num1;
20 while (num1 < num2)
21 {
22 ch1 = chArray1[num1];
23 num1++;
24 switch (ch1)
25 {
26 case '}':
27 if ((num1 < num2) && (chArray1[num1] == '}'))
28 {
29 num1++;
30 }
31 else
32 {
33 StringBuilder.FormatError();
34 }
35 break;
36
37 case '{':
38 if ((num1 < num2) && (chArray1[num1] == '{'))
39 {
40 num1++;
41 }
42 else
43 {
44 num1--;
45 break;
46 }
47 break;
48 }
49 chArray1[num4++] = ch1;
50 }
51 if (num4 > num3)
52 {
53 this.Append(chArray1, num3, num4 - num3);
54 }
55 if (num1 == num2)
56 {
57 return this;
58 }
59 num1++;
60 if (((num1 == num2) || ((ch1 = chArray1[num1]) < '0')) || (ch1 > '9'))
61 {
62 StringBuilder.FormatError();
63 }
64 int num5 = 0;
65 do
66 {
67 num5 = ((num5 * 10) + ch1) - 0x30;
68 num1++;
69 if (num1 == num2)
70 {
71 StringBuilder.FormatError();
72 }
73 ch1 = chArray1[num1];
74 }
75 while (((ch1 >= '0') && (ch1 <= '9')) && (num5 < 0xf4240));
76 if (num5 >= args.Length)
77 {
78 throw new FormatException(Environment.GetResourceString("Format_IndexOutOfRange"));
79 }
80 while ((num1 < num2) && ((ch1 = chArray1[num1]) == ' '))
81 {
82 num1++;
83 }
84 bool flag1 = false;
85 int num6 = 0;
86 if (ch1 == ',')
87 {
88 num1++;
89 while ((num1 < num2) && (chArray1[num1] == ' '))
90 {
91 num1++;
92 }
93 if (num1 == num2)
94 {
95 StringBuilder.FormatError();
96 }
97 ch1 = chArray1[num1];
98 if (ch1 == '-')
99 {
100 flag1 = true;
101 num1++;
102 if (num1 == num2)
103 {
104 StringBuilder.FormatError();
105 }
106 ch1 = chArray1[num1];
107 }
108 if ((ch1 < '0') || (ch1 > '9'))
109 {
110 StringBuilder.FormatError();
111 }
112 do
113 {
114 num6 = ((num6 * 10) + ch1) - 0x30;
115 num1++;
116 if (num1 == num2)
117 {
118 StringBuilder.FormatError();
119 }
120 ch1 = chArray1[num1];
121 }
122 while (((ch1 >= '0') && (ch1 <= '9')) && (num6 < 0xf4240));
123 }
124 while ((num1 < num2) && ((ch1 = chArray1[num1]) == ' '))
125 {
126 num1++;
127 }
128 object obj1 = args[num5];
129 string text1 = null;
130 if (ch1 != ':')
131 {
132 goto Label_0253;
133 }
134 num1++;
135 num3 = num1;
136 num4 = num1;
137Label_01E8:
138 if (num1 == num2)
139 {
140 StringBuilder.FormatError();
141 }
142 ch1 = chArray1[num1];
143 num1++;
144 switch (ch1)
145 {
146 case '{':
147 if ((num1 < num2) && (chArray1[num1] == '{'))
148 {
149 num1++;
150 goto Label_0232;
151 }
152 StringBuilder.FormatError();
153 goto Label_0232;
154
155 case '}':
156 if ((num1 < num2) && (chArray1[num1] == '}'))
157 {
158 num1++;
159 }
160 else
161 {
162 num1--;
163 if (num4 > num3)
164 {
165 text1 = new string(chArray1, num3, num4 - num3);
166 }
167 goto Label_0253;
168 }
169 break;
170 }
171Label_0232:
172 chArray1[num4++] = ch1;
173 goto Label_01E8;
174Label_0253:
175 if (ch1 != '}')
176 {
177 StringBuilder.FormatError();
178 }
179 num1++;
180 string text2 = null;
181 if (formatter1 != null)
182 {
183 text2 = formatter1.Format(text1, obj1, provider);
184 }
185 if (text2 == null)
186 {
187 if (obj1 is IFormattable)
188 {
189 text2 = ((IFormattable) obj1).ToString(text1, provider);
190 }
191 else if (obj1 != null)
192 {
193 text2 = obj1.ToString();
194 }
195 }
196 if (text2 == null)
197 {
198 text2 = string.Empty;
199 }
200 int num7 = num6 - text2.Length;
201 if (!flag1 && (num7 > 0))
202 {
203 this.Append(' ', num7);
204 }
205 this.Append(text2);
206 if (flag1 && (num7 > 0))
207 {
208 this.Append(' ', num7);
209 }
210 goto Label_004E;
211}
212
213
214