接口,其实并不难理解。就是一组抽象成员的集合。 其成员只能是方法和属性的签名,不能有具体实现。
而且接口的成员也不指定修饰符(因为所有接口成员都是隐匿公共的和抽象的)。当一个类或者结构实现包含同名成员的接口,
这时我们可以通过显式实现解决命名冲突。
大致模式如下:
returnType InterfaceName.MethodName(params)
注意:此时,不能提供访问修饰符,因为显式实现的成员总是自动为私有的。也就是说这些显式实现的成员在对像级别是不可用的。
下面介绍几种常用的预定义接口:
一. 构建可处置类型
//命名空间是System
public interface IDisposable { void Dispose(); }
如果一个类或结构提供了IDisposable接口,就是假设当对象用户不再使用这个对象时,会在这个对象引用离开作用域之前手工调用Dispose()。这样,对象可以执行任何必要
的非托管资源(也可以是托管资源)的清除工作,而且不会再有将对象放在终结队列(Finalize()方法的做法)上导致的性能损失,也不必等待垃圾回收器触发类的终结逻辑。
C#的using关键字可以自动调用此接口的Dispose()方法。
二. 构建可枚举类型
//命名空间为 System.Collections
public interface IEnumerable { IEnumerator GetEnumerator(); } public interface IEnumerator { bool MoveNext(); //将游标的内部位置向前移动 object Current {get;} //获取当前的项(只读属性) void Reset(); //将游标重置到第一个成员前面 }
任何支持GetEnumerator()方法的类型都可以通过foreach结构进行运算。如果我们想让自定义的类型支持这些接口 ,可以手工的实现上面的每个方法,但这需要花费不少
精力。这里可以利用System.Array(所有数组的基类)和其他许多类型已经实现了这两个接口的性质,来以简单委托请求到System.Array。
public 自定义类:IEnumerable { 。。。 public 自定义类的构造函数 ; 此类中的另一个自定义类型的数组; public IEnumerator GetEnumerator() { //返回数组对象的IEnumerator return 自定义类型的数组名.GetEnumerator(); } }
此处,要补充说明一下迭代器的构造。
如果我们希望构建支持foreach枚举的自定义集合,可以通过实现IEnumerable接口(可能还有IEnumerator接口),还可以通过迭代器来达到相同目的。
迭代器就是这样一个成员方法,它指定了容器内部项被foreach处理时该如何返回。此时,迭代器方法还必须命名为:GetEnumerator(),返回值还是必须为IEnumerator类型
,但自定义类不需要实现原来那些接口了,即可以不用继承这些接口的了。
迭代器主要是应用yield关键字来定义。
public IEnumerator GetEnumerator() { yield return 数组[0]; yield return 数组[1]; yield return 数组[2]; yield return 数组[3]; .... //或者可以使用内部foreach逻辑迭代每个子项 }
使用yield return语法向调用方返回每个自定义类型对象。yield关键字用来向调用方的foreach结构指定返回值。当到达yield return语句后,当前位置被存储下来,下次调用迭代
器会从这个位置开始执行。
注:System.Array继续了IEnumerable接口,而它又是所有数组类型的基类。这样,我们得到结论:
任何数组类型的类或结构都可以支持foreach语法。如果我们希望自定义的非数组类型的类或结构也可以支持foreach,则可以简单委托到数组类型的相关实现上,以达到简化代码的目的。
三.构建可克隆的对象
using System ; public interface ICloneable { object Clone(); //注意其返回类型为object }
其作用是使自己的自定义类型支持向调用方返回自身同样的副本的能力。
补充:System.Object(超级父类)中定义了一个名为MemerwiseClone()的成员。此方法用来获取当前对象的一分浅复制。因为它是受保护的,对象用户不会直接调用这个方法,而一个对象可能在克隆过程中自己调用这个方法。
如果想要支持真正的深复制,则可以实现此接口。但需要在克隆过程中创建每个引用类型变量的新实例。
概括一下克隆过程:
如果有一个仅包含值类型的类或结构,使用MemerwiseClone()实现Clone()方法。此时,就相当于直接赋值的形式。实际上,直接赋值就是隐式的调用了MemerwiseClone()方法。
如果有一个保存其他引用类型的自定义类型,需要建立一个考虑了每个引用类型成员变量的新对象。
四. 构建可比较的对象
//命名空间System public interface IComparable { int CompareTo(object o); }
它指定了一种允许一个对象可基于某些特定键值进行排序的行为。
System.Array类定义了一个名为Sort()静态方法。在内置类型(如int,short,string等)上调用这个方法的时候,可以以数字或字母顺序对数组中的项排序,因为这些内置数据类型实现了IComparable接口。同理,构建自定义类型的时候,也可以通过实现此接口以使类型数组可被排序。
CompareTo()方法背后的逻辑是,根据某个特定数据字段比较传入的对象与当前实例。当其返回值小于0时,这个实例在指定对象之前,大于0则在指定对象之后,等于0时等于指定对象。
五.指定多个排序顺序
//比较两个对象的通用方法 //命名空间:System.Collections interface IComparer { int Compare(object o1,object o2); }
与IComparable接口不同,IComparer接口不是在要排序的类型中,而是在许多辅助类中实现的,其中每个排序各有一个依据。