zoukankan      html  css  js  c++  java
  • 《C#图解教程》读书笔记之六:接口和转换

    本篇已收录至《C#图解教程》读书笔记目录贴,点击访问该目录可获取更多内容。

    一、接口那点事儿

      (1)什么是接口?

      一组函数成员而未实现的引用类型。只有类和结构能实现接口。

      (2)从IComparable接口看接口实例:

      假设有如下一段代码,它使用Array类的一个静态方法Sort对一个未排序的int类型数组进行排序,并输出排序后的结果。

    using System;
    
    class Program
    {
       static void Main()
       {
          var myInt = new[] { 20, 4, 16, 9, 2 };       // Create an array of ints.
    
          Array.Sort( myInt );                         // Sort elements by magnitude.
    
          foreach ( var i in myInt )                   // Print them out.
             Console.Write( "{0} ", i );
       }
    }

      Sort方法在int类型数组的排序工作上做的很好,但是如果我们尝试在自定义的类上使用就会发生异常,例如下面的MyClass类。

    class MyClass
    {
       public int TheValue;
    }

      Sort为何不能对MyClass进行排序,原因在于:它不知道如何比较自定义对象及如何进行排序。Array类的Sort方法其实依赖于一个IComparable的接口,它声明在BCL中,包含唯一的CompareTo方法。它接收一个object类型的参数,可以匹配任何引用类型。

    public interface IComparable
    {
        int CompareTo(object obj);
    }

      这下,我们知道了int类型默认实现了IComparable接口,而我们的MyClass则没有。因此,我们需要将MyClass实现这个IComparable接口。

    class MyClass : IComparable                          
    {
       public int TheValue;
       public int CompareTo( object obj )                 
       {
          MyClass mc = (MyClass) obj;
    
          if ( this.TheValue < mc.TheValue )
             return -1;
    
          if ( this.TheValue > mc.TheValue )
             return 1;
    
          return 0;
       }
    }

      现在,MyClass类实现了IComparable接口,它可以用于Sort方法了。

    class Program
    {
       static void PrintOut( string s, MyClass[] mc )
       {
          Console.Write( s );
          foreach ( var m in mc )
             Console.Write( "{0} ", m.TheValue );
    
          Console.WriteLine( "" );
       }
    
       static void Main()
       {
          var myInt = new[] { 20, 4, 16, 9, 2 };
    
          MyClass[] mcArr = new MyClass[5];               
          for ( int i = 0; i < 5; i++ )                   
          {
             mcArr[i] = new MyClass();
             mcArr[i].TheValue = myInt[i];
          }
    
          PrintOut( "Initial Order: ", mcArr );           
    
          Array.Sort( mcArr );                            
          PrintOut( "Sorted Order:  ", mcArr );           
       }
    }

      现在,一个完整的接口实例已经完毕。

      (3)使用接口注意事项:

        ①声明接口时:不能包含:数据成员、静态成员;只能声明:方法、属性、事件、索引器;

    TIP:接口允许有任何的访问修饰符,但是接口成员是隐式public的,不允许有任何的访问修饰符,包括public。

        ②实现接口时:在基类列表中包括接口名称;为每一个接口的成员实现接口;

      (4)接口是一种引用类型:我们不能直接通过类或对象的成员访问接口,然而,我们可以通过把类对象转换成接口类型来获取指向接口的引用。一旦有了接口的引用,我们就可以使用点号来调用接口的方法。

    using System;
    
    interface IIfc1
    {
       void PrintOut( string s );
    }
    
    class MyClass : IIfc1
    {
       public void PrintOut( string s )
       {
          Console.WriteLine( "Calling through:  {0}", s );
       }
    }
    
    class Program
    {
       static void Main()
       {
          MyClass mc = new MyClass();         
          mc.PrintOut( "object" );           
    
          IIfc1 ifc = (IIfc1) mc;            
          ifc.PrintOut( "interface" );       
       }
    }

      下面我们看看上面的代码在内存中的分配:

      (5)接口和as运算符=>天生一对

      在以往使用接口引用时,我们往往会使用强制类型转换,但强制类型转换会抛出异常(异常是指代码中的意外错误,它会严重降低代码速度)。如何避免这个问题,我们可以使用as运算符,在类对象未实现接口时不会抛出异常,只会返回null。

    二、看我72变:转换

      (1)本质:接受一个类型的值并使用它作为另一个类型的等价值的过程

      (2)转换分类:

      ①预定义的转换:数字、装箱/拆箱、引用转换;

      数字类型的转换详见下图:

      装箱/拆箱是一个比较重要的点,现在我们来看看:

      装箱(boxing)是值类型->引用类型,本质其实是创建副本。装箱是一种隐式转换,它接收值类型的值,根据这个值在在堆上创建一个完整的引用类型对象并返回对象引用。

      拆箱(unboxing)是引用类型->值类型,本质把装箱后的对象转换回值类型。拆箱是显示转换。

      ②用户自定义的转换:隐式和显示的自定义转换;

    using System;
    
    class Person
    {
       public string Name;
       public int Age;
    
       public Person( string name, int age )
       {
          Name = name;
          Age = age;
       }
    
       public static implicit operator int( Person p ) 
       {
          return p.Age;
       }
    
       public static implicit operator Person( int i ) 
       {
          return new Person( "Nemo", i ); 
       }
    }
    
    class Program
    {
       static void Main()
       {
          Person bill = new Person( "bill", 25 );
    
          int age = bill;
          Console.WriteLine( "Person Info: {0}, {1}", bill.Name, age );
    
          Person anon = 35;
          Console.WriteLine( "Person Info: {0}, {1}", anon.Name, anon.Age );
       }
    }
    View Code

      (3)is运算符:

      在转换过程中,有些转换是不成功的,并且会在运行时抛出一个InvalidCastException异常。我们可以使用is运算符来检查转换是否会成功,从而避免盲目地尝试转换

    本章思维导图

    附件

      思维导图(jpg、pdf以及mmap源文件)下载:http://pan.baidu.com/s/1qWNOGGW

  • 相关阅读:
    多个相同结构的表的字段的修改、添加
    SQL SERVER 查询去重 PARTITION BY
    message from server: "Host 'xxx' is not allowed to connect to th
    jdk 1.8 连接数据库
    恢复SQLServer数据库后,如何同步登陆名和用户名
    无法识别的属性“targetFramework”。请注意属性名称区分大小写。错误解决办法
    jquery.tablesorter 使用
    MD5加密
    C# 判断是否是节假日
    word ladder
  • 原文地址:https://www.cnblogs.com/edisonchou/p/3705240.html
Copyright © 2011-2022 走看看