《C#图解教程》读书笔记之六:接口和转换

时间:2021-08-26 08:18:41

  (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 ); } }

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

《C#图解教程》读书笔记之六:接口和转换

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

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

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

《C#图解教程》读书笔记之六:接口和转换

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

  (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" ); } }

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

《C#图解教程》读书笔记之六:接口和转换

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

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

《C#图解教程》读书笔记之六:接口和转换

二、看我72变:转换

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

《C#图解教程》读书笔记之六:接口和转换

  (2)转换分类:

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

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

《C#图解教程》读书笔记之六:接口和转换

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