.Net RuntimeExplorer开发日志(八) IL to C# - 异常、泛型约束与其它补完
约束指的是泛型类型约束,就是where关键字。作为非科班出身的我来说,逆变协变这个东西真是头一次听说,看了下介绍才明白,以前打过交道,只是当时不知其名而已,又花了些时间,才搞懂如何反射它。类类型的里有个属性名为GenericParameterAttributes,看这个名字就知道了吧,但此属性有个前提,类型必须是IsGenericParameter也就是必须是泛型类型中的虚类型,同样此泛型类型的其它约束也在此中标明。
这个when关键字作用于异常的catch语句,为异常的判断增加了条件过滤,在IL层面上他则是独立于catch块之前的一个名为filter的块,这个块与catch块一样初始时栈里有一个异常的引用。通判断这个引用的类型来执行不同的catch块,这是由CLR来完成的功能,而filter块通常是由一个出栈语句和一组判断语句构成,以ldc.i4.0和cgt.un语句结尾,表示这个filter块的结果,如果结果是1才会执行其对应的catch块。所以对filter的解析则是忽略前后,将中间的判断语句变为if的condition即可。如果这个filter块中需要使用栈里的异常引用,那在编译器的正常代码中会有一个isinst类型强制转换,同样也会有dup语句和后面的非null判断。如果是多个条件判断的话,会被解析成嵌套的三目语句,如果代码未经过混淆,那么则可以根据三目的value1的值来判断是and还是or,最终向其合并为condition语句,而这里三目嵌套的顺序和代码顺序是相似的,所以在输出时要区别开来,因为这里是左向右输出了。
异常catch关键字没什么可说的,以一个出栈语句为始,以一个leave语句为终。出栈语句有两种,pop与stloc,为pop则不解析,为stloc则是说明在filter或catch中要使用异常的引用,要在输出类型后显示变量名。还有个fault块,它在C#中并不是关键字,也会被译为catch,只是它并不对使用栈中的异常引用,也没有标记其异常类型,也就是CatchType为空。
还有些大大小小的修改,顺便也记录在此。
return i++;错误点是return语句从栈中取出的writer被dup过,并且在已在前面操作中锁住,所以此writer再添加return关键字时报错,应对方法是重新new一个writer,结果是将此一句变成两句,即:i++;return i;
if("111"!="222"){}此句被解析成了if(!("111"=="222")){},主要是重载操作符没有与当前语境相关联,所以在rewriter中condition的处理上增加对操作符做求反操作。
leave语句的误解,一直以为此句是安全块结束句,现在看来并非,它是br的替代句,当跳转出安全块内时就用这句,如果是跳向inline块,表示为try中的return value;语句,此句就要按br处理。
还有大量的BUG,主要是以逻辑错误为主,还有些符号错误,如在for循环中数组引用超标,变量名大小写错误,没有判断空引用等等。