从IL看强制转换和is,as

1.强制类型转换。

 注意:下面的所有的IL代码都是release版,并且优化之后的。

Is和as的作用不多说,下面主要从IL角度来看一下他们的工作原理。

请看如下代码:

class CastTest

    {

        static void Main(string[]args)

        {

            objecto = "OK!";

            stringstr = (string)o;

            Console.WriteLine(str);

        }

}

 

然后使用ILDASM查看他的IL代码,如下:

 

 

首先,使用ldstr指令将对象“OK“的引用加载到栈上,然后使用stloc.0指令将引用赋值给变了o。因此,ldstr  “OK” 和stloc.0相当于object  o=”OK“。

注:stloc.0指令的全写为:“store the value on the top of stack  to  thefirst local. “意思将栈顶元素存储到第一个局部变量中。IL栈分为三个部分:参数区,局部变量区,计算栈。可以将他们分别看成一个数组,要访问他们都需要通过下标索引,譬如想要将第一个局部变量加载到计算栈上,就可以使用ldloc.0指令,其中0就是索引0.如果想要将计算栈顶元素存储到局部变量区中的第0个局部变量就可以使用stloc.0指令。

接下来,ldloc.0指令将变量o加载到计算栈中,然后使用castclass指令将o强制转换为System.String。

这里的核心指令是castclass,需要注意这个指令在转换不成功的时候,会抛出一个InvalidCastException异常。因此,在高级语言中一般建议不使用强制类型转换,而是使用可替代的is或者as关键字。


2.Is和as

由于使用强制转换可能会在运行的时候抛出一个异常,所以作为替代,C#提供了另一种类型转换方式,使用这种转换方式,即使在转换不成功的时候,也不会抛出一个异常,这就是使用关键字is和as来实现的。

修改上述代码如下:

class CastTest

    {

        static void Main(string[]args)

        {

            objecto = "OK!";

            stringstr = o as string;

            Console.WriteLine(str);

        }

    }


编译后,查看他的IL代码,如下:

 

这一次,C#没有生成castclass指令,而是生成了一个isinst指令。这个指令弹出栈顶元素,然后将其准换为System.String类型,如果转换成功那么就将转换后的类型压入栈顶,如果转换失败,那么就将一个null入栈,而不是抛出一个异常。

因此,我们只需要检查结果是否为null,就可以知道转换是否成功。

事实上,编译器为不仅仅为as关键字生成了isinst指令,也为is关键字生成了isinst。将上述代码修改如下:

class CastTest

    {

        static void Main(string[]args)

        {

            objecto = "OK!";

            if(o is string)

            {

                //然后可以使用你想要的方式进行转换

            }

          

        }

    }

IL代码如下:


由于is关键字需要一个判断,所以编译器不仅仅会生成一个isinst指令,紧接着还会使用brfalse.s指令来判断转换的结果是否为flase(flase和null都是一个0),如果转换失败就跳转到IL_001b处,否则继续执行下面的指令。

正如你所看到的,编译器会为as关键字生成一个isinst指令,为is关键字生成两个指令:isinst和brfalse。但是,我们一般不会在源代码直接使用as关键字,而是在as之后,在来一个if语句来判断换转是否成功。如下:

 

  class CastTest

    {

        static void Main(string[]args)

        {

            objecto = "OK!";

            stringstr = o as string;

            if(str != null)

            {

                Console.WriteLine(str);

            }

          

        }

    }


查看一下IL代码,会发现什么呢?正如你所想的那样,这时候as和is的效果是一样。那么为什么还要推荐使用as而不是is呢?看一下二者的使用方式便知:

    class CastTest

    {

        static void Main(string[]args)

        {

            objecto = "OK!";

            stringstr = o as string;

            if(str != null)

           {

                Console.WriteLine(str);

            }

          

        }

    }


上面代码只转换一次(string str=o as string)。

 

再看下面代码:

 

    class CastTest

    {

        static void Main(string[]args)

        {

            objecto = "OK!";

 

            if(o is string)

            {

                stringstr = (string)o;

            }

        }

    }


这里却需转换两次,一处在o is string,这里主要使用isinst指令;一处在(string)o,这里使用castclass指令。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值