CTS 1.类型转换

      CTS (Common Type System)及公共类型系统,与C#的类型结构是极为相似的。.NET的C#就是CTS的一个子集。

这里我会从CLR与CLI的角度来思考类型转换。希望每一个人能更加理解 值类型与引用类型的区别,以及明白类型转换。 

      首先是从一段代码开始

using System;


namespace ClassCon
{
     class Foo
    {
         public  override  string ToString()
        {
             return  " F ";
        }
    }
     class Program
    {
         static  void Main( string[] args)
        {
          // 代码段1
            Foo f= new Foo();
            Object o= (Object) f;
            f = (Foo)o;

        // 代码段2
            Object on= new  object();
            Foo fn = (Foo)on;
        }
    }
} //这个程序在代码段2里会出现一个InvalidCastException。

 

      从Foo转到Object是泛化的转换,是类型安全的。 从Object到窄化的转换是可能抛出异常的。但是为什么会有时抛出异常,有时不会呢。从直观角度来看。代码段2的窄化转换肯定会抛出异常,而代码段1不会。这是因为我们有上下文,但是如果脱离上下文怎么判断。而且代码执行的时候它是不会利用这种上下文的。

      前一篇文章会讲过值类型与引用类型的区别。值类型的实例就是值,而引用类型的实例是一个对值的引用,它是一个与机器相关的指针。32位机是4字节。其实还有别的重要区别。值类型没有类型信息,想要获得类型信息需要Box(装箱),而引用类型是有类型信息的。(这是ECMA-335 CLI标准提到的)但是这些类型信息是怎么管理的,我想是由CLR负责的,但是我却一直没弄明白到底CLR是怎么管理的。直到看到《.Net本质论  第1卷:公共语言运行库》里的对象头这个概念与一张图。

虽然微软没有公开资料表示有对象头。但是这东西应该是存在的。因为这很好的表示了4字节的引用类型实例为什么会有类型信息以及CLR怎么判断转换是安全的。

可是这图是有缺陷的,因为它没很好的解释类型转换,先在看看代码

 Foo f= new Foo();
            Object o= (Object) f;
            Console.WriteLine(o.GetType());
            Console.WriteLine(f.ToString());
// 输出结果是:
//     Class.Foo
//    F

       这个输出结果很好的直观表示了为什么窄化有时会成功有时会失败。因为泛化后我们依然有子类或实现接口的类的类型信息。

只要窄化的类可以从原来类型的泛化的话,我们的转换就会成功。 输出结果还表明了引用存储了两个类型信息。

一个是转换前的,还有一个是运行时的类型。前面一个是不会在转换中变得,它是创建对象是得到的。后一个就是转换的本质。它是动态的。

       而前面的对象头并不能描述转换后的类型,所以我想到一个扩展。将htype 一分为二。一个是Satictype。它与上图的htype是一样的,对象创建之后就不会变了。这很好的说明了转换或类型还是不变的。还有一个RuntimeType(名字当然是随意的)。它最开始和Satictype指向是同一位置。但是转换之后。它就会指向转换目标类型的位置。转换到接口就会指向右图接口的htype。父类就会指向父类的htype。这样就很好的解释了子类型为什么有父类型的操作特点。

 

        获得类型与类型转换的时候,CLR会使用Statictype里面的类型信息。当方法调用的时候它会使用RuntimeType里面的信息,会根据转换后的类型信息调用方法。 有了这个认识与理解,我们可以跳跃式类型转换。

 

using System;


namespace ClassCon
{
      interface IFoo
    {
        void Print( string s);

    }
     class Foo:IFoo
    {
        public  void Print( string s)
         {
             Console.WriteLine(s);
         }
         public  override  string ToString()
        {
             return  " F ";
        }
    }
     class Program
    {
         static  void Main( string[] args)
        {
            Foo f= new Foo();
            Object o= (Object) f;
            Console.WriteLine(o.GetType());
            Console.WriteLine(f.ToString());
            ((IFoo)o).Print( " String "); //在这里你以为o是Object类型,但是它却可以直接转换成IFoo类型。
        }
    }
}

 

     这种认识感觉是十分清晰的,不错的收获。其实只要理解底层的话,所有的高级的技术就可以变得直观了。也很好的明白我们是怎么一路走过来的!

 

系列索引:

.NET本质论I:CLI 

 


 

 

 

 

 

转载于:https://www.cnblogs.com/Okalun/archive/2012/11/30/2795875.html

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值