1.什么是接口
接口是指定一组函数成员而不实现它们的引用类型,所以只能类和结构来实现接口。
2.使用IComparable接口的实例
Array.Sort方法在int数组上工作得很好,但是如果我们尝试在自己的类上使用会发生什么呢?
class MyClass
{
public int TheVaule;
}
...
MyClass[] mc=new MyClass[5];
...
Array.Sort(mc);//尝试使用Sort时抛出异常
Array类的Sort方法其实依赖于一个叫做IComparable的接口,它声明在BCL中,包含唯一的方法CompareTo.
public interface IComparable
{
int CompareTo(object obj);
}
它返回以下几个值之一:
- 负数值 当前对象小于参数对象
- 正数值 当前对象大于参数对象
- 零 两个对象在比较时相等
要实现一个接口,类或结构必须做两件事情:
- 必须在基类列表后面列出接口名称
- 必须为接口的每一个成员提供实现
class MyClass:IComparable
{
public int TheVaule;
public int CompareTo(object obj)//引用方法的实现
{
MyClass mc=(MyClass)obj;
if(this.TheVaule<mc.TheVaule) return -1;
if(this.TheVaule>mc.TheVaule) return 1;
return 0;
}
}
3.声明接口
- 接口声明不能包含以下成员
-
- 数据成员
-
- 静态成员
- 接口声明只能包含如下类型的非静态成员函数的声明
-
- 方法
-
- 属性
-
- 事件
-
- 索引器
- 这些函数成员的声明不能包含任何实现代码,而在每一个成员声明的主体后必须使用分号
- 按照惯例,接口名称必须从大写的I开始(如ISaveable)
- 与类和结构一样,接口声明还可以分隔成分部接口声明
接口和接口成员的访问性有重要区别
- 接口声明可以有任何访问修饰符public protected internal,private.
- 然而,接口的成员是隐式Public的,不允许有任何访问修饰符,包括public
4.实现接口
只有类和结构才能实现接口,要实现接口,类或结构必须:
- 在基类列表中包括接口名称
- 为每一个接口的成员提供实现
class MyClass:IMyInterface1
{
int DoStuff(int nVar1,long lVar2)
{...}//实现代码
double DoOtherStuff(string s,long x)
{...}//实现代码
}
- 如果类实现了接口,它必须实现接口的所有成员
- 如果类从基类继承并实现了接口,基类列表中的基类名称必须放在所有接口之前
class Derived:MyBaseClass,Ifc1,IEumerable,IComparable
{
...
}
简单接口的实例
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");//调用方法
}
}
5.接口是引用类型
接口不仅仅是类或结构要实现的成员列表,它是一个引用类型
我们不能直接通过类对象的成员访问接口,然而,我们可以通过把类对象引用强制转换成接口类型来获取指向接口的引用,一旦有了接口的引用,我们就可以使用点号来调用接口的方法
IIfc1 ifc=(IIfc1)mc;//获取接口的引用
ifc.PrintOut("interface");//使用接口的引用调用方法
如果我们尝试将类对象引用强制转换为类未实现的接口的引用,强制转换操作会抛出一个异常,我们可以通过as运算符来避免这个问题
ILiveBirth b= a as ILiveBirth;
6.实现多个接口
- 类和结构可以实现任意数量的接口
- 所有实现的接口必须列在基类列表中并以逗号分隔
7.实现具有重复成员的接口
如果一个类实现了多个接口,并且其中一些接口有相同签名和返回类型的成员,那么类可以实现单个成员来满足所有包含重复成员的接口
class MyClass:IIfc1,IIfc2//实现两个接口
{
public void PrintOut(string s)//两个接口的单一实现
{
Console.WriteLine("Calling through: {0}",s);
}
}
class Program
{
static void Main()
{
MyClass mc=new MyClass();//创建实例
mc.PrintOut("object");//调用方法
}
}
8.派生成员作为实现
实现接口的类可以从它的基类继承实现的代码
interface IIfc1{void PrintOut(string s);}
class MyBaseClass//声明基类
{
public void PrintOut(string s)//声明方法
{
Console.WriteLine("Calling through:{0}",s);
}
}
class Derived:MyBaseClass,IIfc1//声明类
{}
class Program{
static void main()
{
Derived d=new Derived();
d.PrintOut("object.");
}
}
Derived类中不用实现代码也可以实现接口
9.显式接口成员实现
单个类可以实现多个接口需要的所有成员,但是,如果我们希望为每一个接口分离实现该怎么做呢,在这种情况下,我们可以创建显式接口成员实现
interface IIfc1{void PrintOut(string s);}
interface IIfc2{void PrintOut(string t);}
class MyClass:IIfc1,IIfc2
{
void IIfc1.PrintOut(string s)//显式实现
{Console.WriteLine("IIfc1:{0}",s);}
void IIfc2.PrintOut(string s)//显式实现
{Console.WriteLine("IIfc2:{0}",s);}
}
class Program
{
static void Main()
{
MyClass mc=new MyClass();//创建实例
IIfc1 ifc1=(IIfc1)mc;
ifc1.PrintOut("interface 1");
IIfc2 ifc2=(IIfc2)mc;
ifc2.PrintOut("interface 2");
}
}
以上代码没有指向类级别实现,如果有显式接口成员实现,类级别的实现是允许的,但不是必须的,因此,我们有如下三种实现场景:
- 类级别实现
- 显式接口成员实现
- 类级别和显式接口成员实现
访问显式接口成员实现
显式接口成员实现只可以通过指向接口的引用来访问。
class MyClass:IIfc1//声明类
{
public void PrintOut(string s)//实现
{
Console.WriteLine("Calling through: {0}",s);
}
public void Mythod1()
{
PrintOut("...");//编译错误
this.PrintOut("...");//编译错误
((IIfc1)this).PrintOut("...");//转换为接口引用
}
}
这个限制对继承产生了重要的影响,由于其他类成员不能直接访问显式接口成员实现,派生类的成员也不能直接访问它们,它们必须总是通过接口的引用来访问。
10.接口可以继承接口
之前我们已经知道接口实现可以从基类被继承,而接口本身也可以从一个或多个接口继承
interface IDataIO:IDataRetrieve,IDataStore
{...}
- 与类不同,它在基类列表只能有一个类名,而接口可以在基接口列表中有任意多个接口
-
- 列表中的接口本身可以继承其他接口
-
- 结果接口包含它声明的所有接口和所有基接口的成员