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


Posted on 2006-10-20 01:10 Chagel 阅读(2374) 评论(10) 编辑 收藏

Feedback

#1楼  回复 引用 查看   

2006-10-20 07:09 by 兰亭      
这个不太清楚。在String.Format中如果要加大括号的话,需要一次加两个。比如:
string script = String.Format(
@"
function getControl()
{{
return document.getElementById('{0}');
}}
", id);

#2楼  回复 引用 查看   

2006-10-20 08:59 by 心不在焉      
恩,这就跟sql里面你要转义单引号防止注入一样,需要写2次的。

#3楼  回复 引用   

2006-10-20 09:32 by ^_^[未注册用户]
恩, 研究得不错

#4楼[楼主]  回复 引用 查看   

2006-10-20 09:33 by Chagel      
是的,我们从源代码中也能看到是如何进行转义的:

if ((num1 < num2) && (chArray1[num1] == '}'))
28 {
29 num1++;
30 }

case '{':
38 if ((num1 < num2) && (chArray1[num1] == '{'))
39 {
40 num1++;
41 }

#5楼  回复 引用 查看   

2006-10-20 09:36 by 出走的影子      
兰亭 正解

#6楼  回复 引用   

2006-10-20 09:50 by 木野狐[匿名]
{{
}}
""

#7楼[楼主]  回复 引用 查看   

2006-10-20 10:25 by Chagel      
这篇post是要讨论原代码中如何过滤字符串,以引导我们正确使用format字符串。请大家不要偏航 :)
大家有时间仔细看一下AppendFormat方法吧,有点挑战的!

#8楼  回复 引用   

2006-10-20 17:11 by xxxx[未注册用户]
9 int num1 = 0;
10 int num2 = chArray1.Length;
11 char ch1 = '\0';
19 int num4 = num1;
20 while (num1 < num2)
21 {
22
49 chArray1[num4++] = ch1;
50 }

这个你再仔细看看,哪里有问题?

chArray1[++num4] = ch1; 才会有问题

#9楼[楼主]  回复 引用 查看   

2006-10-20 17:23 by Chagel      
To XXXX.
thanks for your comment.

不知道你有没有注意到44行 :
num1--;

如果在同一循环中num4已经大于num1,你看会不会有问题?

#10楼  回复 引用 查看   

2006-10-20 20:52 by 维生素C.NET      
如果用使用堆栈来检测语法和内部匹配情况比这样做就要麻烦了,这样做是不是也算是"转义"?
本作品采用知识共享署名-非商业性使用-相同方式共享 2.5 中国大陆许可协议进行许可。

©2005-2009. Chen Gang