一、什么是接口
- 含义:接口是指定一组函数成员而不实现它们的引用类型。(只能用类和结构实现接口)
- 接口可以包含实例方法、属性、事件、索引器或这四种成员类型的任意组合。
- 接口可以包含静态构造函数(不能创建接口的实例)、字段、常量或运算符
二、声明接口
- 按照惯例接口名称应该以大写的“I”开头。
- 接口声明可以有任何的访问修饰符(public、protected、internal、private)。
- 根据需求,在接口中声明没有方法体的函数成员(方法体使用分号代替)。
- 接口的成员是隐式public,不允许private访问修饰符
三、实现接口
- 只有类和结构才能实现接口。
- 实现方法:在基类列表中包含接口名,为接口的每一个成员提供实现。
- 抽象类和普通类实现接口有所不同,抽象类可以选择不实现接口中的方法。
四、接口是引用类型
- 接口是引用类型,如果一个类实现了接口,我们可以通过强制转换,把类对象引用强制转换成接口引用。
- 除了强转运算符,我们以可以通过as运算符将对象引用转换为接口引用。
//接口
interface IIfc1
{
void PrintOut(string s);
}
//未实现IIfc1接口的类
class MyClass : IIfc1
{
public void PrintOut(string s)
{
Console.WriteLine("调用者:{0}",s);
}
}
//未实现IIfc1接口的类
class MyClass1 { }
//测试
internal class Program
{
static void Main(string[] args)
{
//例1:可以使用强转运算符将类对象引用转换为接口引用
MyClass mc = new MyClass();
mc.PrintOut("MyClass对象");//调用者:MyClass对象
IIfc1 ifc1 = (IIfc1)mc;
ifc1.PrintOut("IIfc1接口");//调用者:IIfc1接口
//例2:使用as运算符将类对象引用转换为接口引用
//好处:避免将类对象引用转换接口引用失败而抛异常
//如果类实现了接口,表达式返回指向接口的引用
//如果类没有实现接口,表达式返回null而不是抛出异常
MyClass1 myClass1 = new MyClass1();
IIfc1 ifc = myClass1 as IIfc1;
if (ifc != null)
Console.WriteLine("转换成功,IIfc1接口");
else
Console.WriteLine("转换失败,类对象未实现该接口!");
}
}
理解图如下:
五、实现多个接口
类只能单继承,接口可以多实现。实现的多个接口在基类列表中以逗号分隔。
1.实现具有重复成员的接口
如果一个类实现了多个接口,并且其中一些接口有相同签名和返回类型的成员,那么类可以实现单个成员来满足所有包含重复成员的接口。
interface IIfc1 { void PrintOut(string s); }
interface IIfc2 { void PrintOut(string s); }
class MyClass : IIfc1, IIfc2
{
public void PrintOut(string s)
{
Console.WriteLine(s);
}
}
internal class Program
{
static void Main(string[] args)
{
MyClass myClass = new MyClass();
myClass.PrintOut("一个实现方法实现多个相同返回类型及签名的接口");
}
}
2.多个接口的引用
如果类实现了多个接口,我们可以获取每一个接口的独立引用。
interface IIfc1 { void PrintOut(string s); }
interface IIfc2 { void PrintOut(string s); }
class MyClass : IIfc1, IIfc2
{
public void PrintOut(string s)
{
Console.WriteLine(s);
}
}
internal class Program
{
static void Main(string[] args)
{
MyClass myClass = new MyClass();
myClass.PrintOut("一个实现方法实现多个相同返回类型及签名的接口");
IIfc1 ifc1 = (IIfc1)myClass;
IIfc2 ifc2 = (IIfc2)myClass;
ifc1.PrintOut("接口1");
ifc2.PrintOut("接口2");
}
}
3.显式接口成员实现
- 我们可以使用限定接口名称显式地为每一个接口分别进行实现。
- 实现类中的显示接口成员实现只可以通过指向接口的引用来访问。
interface IIfc1 { void PrintOut(string s); }
interface IIfc2 { void PrintOut(string s); }
class MyClass : IIfc1, IIfc2
{
void IIfc1.PrintOut(string s)
{
Console.WriteLine("IIfc1:{0}",s);
}
void IIfc2.PrintOut(string s)
{
Console.WriteLine("IIfc2:{0}", s);
}
public void Method()
{
PrintOut("光头强");//编译报错
this.PrintOut("熊大");//编译报错
((IIfc1)this).PrintOut("熊二");//显式接口成员实现只可以通过指向接口的引用来访问
}
}
internal class Program
{
static void Main(string[] args)
{
MyClass myClass = new MyClass();//创建类对象
IIfc1 ifc1 = (IIfc1)myClass;//获取IIfc1的引用
ifc1.PrintOut("接口1");
IIfc2 ifc2 = (IIfc2)myClass;//获取IIfc2的引用
ifc2.PrintOut("接口2");
}
}
六、派生成员作为实现
实现接口的类可以从它的基类继承实现的代码。
interface IIfc1 { void PrintOut(string s); }
class MyBaseClass
{
public void PrintOut(string s)
{
Console.WriteLine(s);
}
}
class Derived : MyBaseClass,IIfc1
{
//Derived中是空的
}
internal class Program
{
static void Main(string[] args)
{
Derived derived = new Derived();
IIfc1 ifc1 = derived as IIfc1;//转换为指向IIfc1的引用
if (ifc1 != null)
ifc1.PrintOut("从接口的引用调用PrintOut,这个方法被Derived的基类MyBaseClass实现");
}
}
七、接口可以多继承
- 接口可以从一个或多个接口继承。
- 结果接口包含它继承的所有接口和所有基接口的成员。
八、不同的类实现一个接口
综合练习:
//接口
interface ILiveBirth
{
string BabyCalled();
}
//动物类
class Animal { }
//狗狗
class Dog : Animal, ILiveBirth
{
public string BabyCalled()
{
return "puppy";
}
}
//猫猫
class Cat : Animal, ILiveBirth
{
public string BabyCalled()
{
return "Kitten";
}
}
//鸟
class Bird : Animal { }
//测试
internal class Program
{
static void Main(string[] args)
{
Animal[] animals = new Animal[3];
animals[0] = new Bird();
animals[1] = new Cat();
animals[2] = new Dog();
foreach (Animal animal in animals)
{
ILiveBirth? lb = animal as ILiveBirth;
if (lb != null)
Console.WriteLine("BabyCalled:{0}", lb.BabyCalled());
}
}
}
九、总结
- 接口是指定一组函数成员而不实现它们的引用类型。
- 接口只能被类和结构实现。
- 接口中可以包含实例方法、属性、事件、索引器、字段、常量和运算符。
- 接口的成员是隐式public,不允许private访问修饰符。
- 接口可以继承多个接口。
- 抽象类可以选择实现接口中的方法,普通类必须实现接口中的方法。
- 接口不能创建对象,实现接口的类对象引用可以转换为接口引用。
- 实现类中的显示接口成员实现只可以通过指向接口的引用来访问。
- 实现接口的类可以从它的基类继承实现的代码。
(注:本章学习总结自《C#图解教程》)