从is和as想到Is-A、Has-A和Use-A(一)

       面向对象的编程语言(如C#Java),都不可避免要在编写代码的过程中进行类型转换。类型转换虽然看似很简单,但在实际工作中仍是一件很让人头痛的事儿,特别是初学者,很多时候类型转换真正转起来的时候会很晕(我曾晕过,哈哈)。C#为我们做引用类型的转换提供了一个操作符asas只能操作引用类型,还有一个用于类型判断的isis操作符可以操作值类型和操作类型。关于值类型转换,值类型与引用类型的相互转换在本文中不涉及。

    关于isas可以参考:

http://www.cnblogs.com/anytao/archive/2007/04/07/must_net_01.html#commentformisMSDN中的解释是:检查对象是否与给定类型兼容。as的解释是:用于在兼容的引用类型之间执行某些类型的转换。看到很多书里说到做类型转换时用as比用is性能高,至于怎么个高法,其实真的很无聊,哈哈,我自这么认为。有的人干脆直接说asis性能高,我认为asis如果单独比较,而不是用于类型转换这个过程的话,性能应该一样(这个过程中只所以产生性能的差别,其实是类型判断和是否为null判断之间的差别。),甚至is有时可能比as还要高,这个只是猜想,有空验证一下。asis用于引用类型时,它们的共同点是都做非空判断、类型判断,都做返回操作;不同的是当对象为null时,as直接返回一个空值,is返回false;当类型不兼容时,as会返回一个null值,is返回false,成功时返回as操作符前的对象引用,is返回一个true值。

    类型转换的核心是类型兼容,那么什么是类型兼容的呢?其实可以用面向对象中的“里氏代换原则”来解释:所有父类能出现的地方,都可以用子类来替换。

    还是看一个例子吧:

       public class A

{

   //……

    }

    public class B : A

    {

        //……

}

首先定义一个类A,B继承A

public class C

    {

        public void LoadA(A a)

        {

           //……

        }

        public void LoadB(B b)

        {

           //……

        }

 }

C中有两个方法,一个定义A类型的作为参数,一个定义B类型作为参数。

static void Main(string[] args)

{

           C c = new C();

            c.LoadA(new A());//正确

            c.LoadA(new B());//正确

            c.LoadB(new B());//正确

        c.LoadB(new A());//错误无法从“A”转换为“B

}

客户端调用LoadA时,传入A类型实例和B类型实例都可以,因为BA的子类,所以根据“里氏代换原则”这是成立的;但是反过来就不成立,如调用LoadB时传入A类型实例时,编译都通不过,看来编译器帮助我们进行了“里氏代换原则”的检查。

C#规定我们在做类型转换时,子类对象可以隐式转换为父类对象,如:

A a = new B();

而反过来就要做显示转换,如:

A a = new B();

B b = (B)a;//强制转换

这个例子很好理解,但如果是这样呢?

A a = new A();

B b = (B)a;//可以通过编译,但会产生一个运行时错误。

看到一些人对上面的现象很不理解,为什么第一个没错,而第二个有错呢?

C#规定在进行类型转换时,被转换的实例类型必须是要转换类型的自身或它的子类,上例中变量a的类型为A,但它引用实际类型也是A;而A并不是B的子类,而是B的父类,当然不会成功。其实也不难理解,例如B类中声明了一个A中不存在的方法Abc,把A实例转为B类型就算成功,但是如果你调用b.Abc()A实例中肯定是没有的。还有一点就是,类型变量是被分配在内存栈里,而我们用new B()实例化一个对象会被分配到堆里,类型变量我们可以把它看成一个保存对象地址的容器,也可理解为指向一个对象的指针,真正的操作是在堆中进行的。像A a = new A()a这个变量就指向一个类型为A的实例的;A a = new B();这时变量a指向的就是B对象,BA的子类,BA类所有的特性,而反过来,A可能不具有B的所有特性,所以我们就可以理解为什么A的实例不能转换为B类型了。在类型转换中一定要分清类型变量和类型实例的区别,这样才不至于迷茫。无论一个变量是什么类型,只要用GetType()方法来获取它引用的实例的真实类型,如:

A a = new B();

Console.WriteLine(a.GetType().Name);

显示为B

在说一点isas的事吧,在我们用isas时。

:

A a = new A();

B b = a as B;

这里不会抛出异常(任何地方都不会,哈哈,当然你写错例外),只是a as B会返回一个null值,所以要想转换成功,a引用的对象的类型必须是B类型或B类型的子类才能转换成功,成功与否和a变量的类型无关。

Isas用法一样,只是返回值不同,

如:

A a = new A();

bool isCompatible = a is B;

is操作符也不会抛出异常,a is B这里a引用的对象的类型必须是B类型或B类型的子类才会返回true值,同样,是否返回true值也跟a变量的类型无关。

 

 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值