C#接口(interface)的用法(非常详细)
C# 程序中,当普通类继承了抽象类后,其实就形成了 IS-A 关系。
例如,我们声明鸟的抽象类 Bird,可以定义飞行抽象方法 Flying(),现在我们创建一个老鹰类 Eagle 继承 Bird 类,然后可以让老鹰类重写飞行方法 Flying(),在这种关系下我们可以说老鹰是一种鸟,所以我们说这是 IS-A 关系。
本节要讲的接口(interface)就比较像是“有同类的行为”。例如,鸟会飞行,飞机也会飞行,然而这是两个完全不同的物种。如果只因为飞行就让鸟类去继承飞机类或是让飞机类去继承鸟类,都是不恰当的,就可以使用接口解决这方面的问题,我们可以设计飞行接口 Fly,然后在这个接口内定义 Flying() 抽象方法,所定义的抽象方法让飞机类和鸟类去实现,这也是接口的基本概念。
程序定义接口时习惯会将第 1 个英文字母用大写,这是为了可以快速区分接口,例如下列接口定义 IAnimal 左边第 1 个英文字母是 I:
【实例 1】最基本的类实现接口的实例。
这个概念也可以应用在接口中,详情可以参考下列实例。
【实例 2】使用 upcasting 概念重新设计实例 1。
使用 upcasting 的限制是只可以调用接口有定义的方法,如果调用类内非接口定义的方法会产生编译错误,可以参考下列实例。
对上例进行扩充,尝试调用非接口方法 Life 有错误产生:
【实例 3】修订实例 1,将 dog 改为是 Dog 类的对象,则程序可以正常运作。
接下来用多个实例讲解接口在不同状况下的应用。
可以用下图来说明上述程序实例:
另外在声明对象时,笔者用了向上转型的方式声明对象,当然读者也可以使用下列方式分别声明 Bird 和 Airplane 类对象:
【实例 5】设计接口 IGrandfather,此接口有 GrandfatherMethod() 方法。然后设计接口 IFather,此接口有 FatherMethod() 方法,同时此接口继承 IGrandfather。然后设计 John 类,此类实现 IFather,同时重写 GrandfatherMethod() 和 FatherMethod() 方法。
【实例 6】设计 IShape 接口,此接口有定义计算面积的方法 Area(),然后设计 Rectangle 类实操 IShape 接口与其方法 Area()。
显式实现的语法如下:
【实例 7】显式实现的实例,读者可以留意第 6 行、第 7 行和第 8 行的调用,如果省略前方的“//”则会有编译错误产生。
【实例 8】ICoord 接口属性 X、Y 和 Distance 的实现,设计一个 Point 类,此 Point 类实现了 X、Y 和 Distance 属性。
多重继承接口的概念,可参考下图,目前一个类可以实现多个接口,一个接口可以继承多个接口。
基本程序设计概念与前文接口的继承与实现概念相同,当一个类继承实现多个接口时,需要实现这些接口的所有抽象方法。当一个接口继承多个接口时,继承此接口的类需要实现此接口及它所有继承接口的抽象方法。
假设 A 类同时继承 B 与 C 接口,整个语法如下:
【实例 9】扩充实例 6,增加 IColor 接口,这个接口定义颜色。
【实例 10】一个接口 IFly 继承了 IBird 和 IAirplane 接口的应用,InfoFly 类将实现 IFly 接口的 PediaFly 抽象方法,以及它所继承的 IAirplane 接口的 AirplaneFly 抽象方法和 IBird 接口的 BirdFly 方法。
虚拟接口方法可以有完整的实体内容,同时此方法不需要在类内实现。使用时需要留意,类并没有继承接口的虚拟接口方法,所以类对象无法调用虚拟接口方法。
【实例 11】虚拟方法的说明,这个程序的重点是类对象无法调用虚拟方法,所以第 9 行若是拿掉“//”会有错误产生。
例如,我们声明鸟的抽象类 Bird,可以定义飞行抽象方法 Flying(),现在我们创建一个老鹰类 Eagle 继承 Bird 类,然后可以让老鹰类重写飞行方法 Flying(),在这种关系下我们可以说老鹰是一种鸟,所以我们说这是 IS-A 关系。
本节要讲的接口(interface)就比较像是“有同类的行为”。例如,鸟会飞行,飞机也会飞行,然而这是两个完全不同的物种。如果只因为飞行就让鸟类去继承飞机类或是让飞机类去继承鸟类,都是不恰当的,就可以使用接口解决这方面的问题,我们可以设计飞行接口 Fly,然后在这个接口内定义 Flying() 抽象方法,所定义的抽象方法让飞机类和鸟类去实现,这也是接口的基本概念。
C#接口的定义
接口外观和类相似但是它不是类,C# 中接口的定义是 interface,特色如下:- 接口可以像类一样拥有方法、属性、索引器和事件,这些方法和属性只是抽象定义,没有主体内容(C#8.0 以后的版本支持可以有主体内容);
- 每个接口的属性和方法都只是定义,一定有类来实现属性或方法,实现也可想成是重写,但是省略 override 关键词;
- 早期 C# 语言接口不可以有字段,C#8.0 以后的版本支持 static 字段;
- 接口成员特色是 public 和 abstract,因为是默认的,所以程序设计时不用再注明是 public 和 abstract。C#8.0 以后的版本有关接口存取修饰词的限制放宽了,也可以有 private、protected、internal、static、sealed、partial 和 virtual,但默认还是 public;
- 每个接口一定有类来实现其方法,实现方式和继承一样使用“:”符号。一个类实现了一个接口,又称一个类继承了一个接口;
- 接口不可以有构造方法;
- 不可以为接口创建对象。
程序定义接口时习惯会将第 1 个英文字母用大写,这是为了可以快速区分接口,例如下列接口定义 IAnimal 左边第 1 个英文字母是 I:
interface IAnimal // 第1个英文字母用大写字母 I
{
void Action(); // 自动是public和abstract
}
【实例 1】最基本的类实现接口的实例。
Dog dog = new Dog(); // 创建 dog 对象
dog.Action();
interface IAnimal // 接口 IAnimal
{
void Action(); // interface 的 Action 方法
}
class Dog : IAnimal // 继承接口 IAnimal
{
public void Action() // 不含 override
{
Console.WriteLine("狗:在跑步");
}
}
执行结果为:
狗:在跑步
C# upcasting实现接口
upcasting 可以翻译为向上转型,基本概念是一个类本质是子类,但是将它当作父类来看待,然后将父类的引用指向子类对象。这个概念也可以应用在接口中,详情可以参考下列实例。
【实例 2】使用 upcasting 概念重新设计实例 1。
IAnimal dog = new Dog(); // Upcasting
dog.Action();
interface IAnimal // 接口 IAnimal
{
void Action(); // interface 的 Action 方法
}
class Dog : IAnimal // 继承接口 IAnimal
{
public void Action() // 不含 override
{
Console.WriteLine("狗:在跑步");
}
}
执行结果与实例 1 相同。使用 upcasting 的限制是只可以调用接口有定义的方法,如果调用类内非接口定义的方法会产生编译错误,可以参考下列实例。
对上例进行扩充,尝试调用非接口方法 Life 有错误产生:
IAnimal dog = new Dog(); // Upcasting
dog.Action();
dog.Life(); // error
interface IAnimal // 接口 IAnimal
{
void Action(); // interface 的 Action 方法
}
class Dog : IAnimal // 继承接口 IAnimal
{
public void Action() // 不含 override
{
Console.WriteLine("狗:在跑步");
}
public void Life() // Dog 自有方法
{
Console.WriteLine("主人的宠物");
}
}
执行程序会发现,程序编译错误。【实例 3】修订实例 1,将 dog 改为是 Dog 类的对象,则程序可以正常运作。
Dog dog = new Dog(); // 创建 Dog类对象 dog
dog.Action();
dog.Life();
interface IAnimal // 接口 IAnimal
{
void Action(); // interface 的 Action 方法
}
class Dog : IAnimal // 继承接口 IAnimal
{
public void Action() // 不含 override
{
Console.WriteLine("狗:在跑步");
}
public void Life() // Dog 自有方法
{
Console.WriteLine("主人的宠物");
}
}
执行结果为:
狗:在跑步
主人的宠物
C#接口的应用场景
每个面向对象的程序语言都有接口功能,这个功能的主要优点如下:- 安全理由,只显示调用方法的名称与参数,隐藏继承类的细节;
- C# 不支持多重继承,一个类只能有一个父类,但是 C# 支持继承多个接口,使用上更具弹性。
接下来用多个实例讲解接口在不同状况下的应用。
1) 两个类实现一个接口
【实例 4】创建一个 Fly 接口,此接口有 Flying() 方法,然后创建 Bird 和 Airplane 类实现 Fly 接口的 Flying() 方法。
IFly bird = new Bird(); // upcasting
bird.Flying();
IFly airplane = new Airplane(); // upcasting
airplane.Flying();
interface IFly
{
void Flying();
}
class Bird : IFly
{
public void Flying()
{
Console.WriteLine("Flying:鸟在飞");
}
}
class Airplane : IFly
{
public void Flying()
{
Console.WriteLine("Flying:飞机在飞");
}
}
执行结果为:
Flying:鸟在飞
Flying:飞机在飞
可以用下图来说明上述程序实例:

另外在声明对象时,笔者用了向上转型的方式声明对象,当然读者也可以使用下列方式分别声明 Bird 和 Airplane 类对象:
Bird f1_y1 = new Bird(); Airplane f1_y2 = new Airplane();
2) 多层次继承与实现
一个接口可以继承另一个接口,使用的方法是“:”,细节可以参考下列实例。【实例 5】设计接口 IGrandfather,此接口有 GrandfatherMethod() 方法。然后设计接口 IFather,此接口有 FatherMethod() 方法,同时此接口继承 IGrandfather。然后设计 John 类,此类实现 IFather,同时重写 GrandfatherMethod() 和 FatherMethod() 方法。
John john = new John();
john.GrandfatherMethod();
john.FatherMethod();
interface IGrandfather // 祖父接口
{
void GrandfatherMethod();
}
interface IFather : IGrandfather // 父接口继承祖父接口
{
void FatherMethod();
}
class John : IFather // John类实现父接口
{
public void GrandfatherMethod() // 实现祖父方法
{
Console.WriteLine("调用 GrandFatherMethod");
}
public void FatherMethod() // 实现父方法
{
Console.WriteLine("调用 FatherMethod");
}
}
执行结果为:
调用 GrandFatherMethod 调用 FatherMethod可以用下图来说明上述程序实例:

3) 接口方法内含参数
至今所有实现的接口方法都未含参数,这里主要是创建内含参数的方法,让读者可以实际体验。【实例 6】设计 IShape 接口,此接口有定义计算面积的方法 Area(),然后设计 Rectangle 类实操 IShape 接口与其方法 Area()。
Rectangle rectangle = new Rectangle();
rectangle.Area(5, 10);
interface IShape // 定义接口 IShape
{
void Area(int a, int b); // 定义计算面积
}
class Rectangle : IShape // 实现 IShape
{
public void Area(int a, int b) // 计算面积
{
int area = a * b;
Console.WriteLine($"矩形面积:{area}");
}
}
执行结果为:
矩形面积:60
C#接口的显式实现
一个类如果需要设计多个方法实现多个接口方法,使用显式实现可以让整个程序比较容易阅读与了解。显式实现的语法如下:
<InterfaceName>.<MemberName>使用显式实现也是有限制的,非 upcasting 的对象无法调用实现的接口定义的方法。
【实例 7】显式实现的实例,读者可以留意第 6 行、第 7 行和第 8 行的调用,如果省略前方的“//”则会有编译错误产生。
IComputer com = new Software(); // upcasting
Software soft = new Software(); // Software类的soft对象
com.Office();
com.Programming("OK");
//soft.Web("NO"); // 编译错误
//soft.Office(); // 编译错误
//soft.WriteFile("NO"); // 编译错误
soft.Web("OK");
interface IComputer
{
void Office();
void Programming(string text);
}
class Software : IComputer
{
void IComputer.Office() // 显式实现
{
Console.WriteLine("适用一般职员");
}
void IComputer.Programming(string text) // 显式实现
{
Console.WriteLine("适用程序设计师");
}
public void Web(string text)
{
Console.WriteLine("适用网页设计");
}
}
执行结果为:
适用一般职员
适用程序设计师
适用网页设计
C#接口属性的实现
前面重点说明了接口方法的实现,接下来将用实例解说属性的实现。【实例 8】ICoord 接口属性 X、Y 和 Distance 的实现,设计一个 Point 类,此 Point 类实现了 X、Y 和 Distance 属性。
ICoord p = new Point(6, 8); // Upcasting
Console.WriteLine($"(x, y)点位置 x = {p.X}, y = {p.Y}");
Console.WriteLine($"与(0, 0)距离 dist = {p.Distance}");
interface ICoord // 接口
{
int X { get; set; } // 属性 X
int Y { get; set; } // 属性 Y
double Distance { get; } // 属性 - 与(0, 0)的距离
}
class Point : ICoord // 实现ICoord
{
public Point(int x, int y) // Constructor
{
X = x;
Y = y;
}
public int X { get; set; } // 实现属性 X
public int Y { get; set; } // 实现属性 Y
public double Distance => // 实现属性 Distance
Math.Sqrt(X * X + Y * Y);
}
执行结果为:
(x, y)点位置 x = 6, y = 8
与(0, 0)距离 dist = 10
C#接口的多重继承与实现
所谓的多重继承是指一个类可以继承与实现多个接口,C# 语言的类是不支持多重继承的,不过在接口的实现中可以使用多重继承接口。多重继承接口的概念,可参考下图,目前一个类可以实现多个接口,一个接口可以继承多个接口。

基本程序设计概念与前文接口的继承与实现概念相同,当一个类继承实现多个接口时,需要实现这些接口的所有抽象方法。当一个接口继承多个接口时,继承此接口的类需要实现此接口及它所有继承接口的抽象方法。
假设 A 类同时继承 B 与 C 接口,整个语法如下:
interface IB
{
void b(); // 抽象方法 b()
}
interface IC
{
void c; // 抽象方法 c()
}
class A implements IB, IC { // 请留意语法
// 实现 b 和 c;
}
相当于被继承或实操的多个接口之间要有逗号隔开,至于其他规则则不变。【实例 9】扩充实例 6,增加 IColor 接口,这个接口定义颜色。
Rectangle rectangle = new Rectangle();
rectangle.Area(5, 10);
rectangle.Color();
interface IShape // 定义接口 IShape
{
void Area(int a, int b); // 定义计算面积
}
interface IColor // 定义色彩
{
void Color();
}
class Rectangle : IShape, IColor // 实现 IShape 和 IColor
{
public void Area(int a, int b) // 计算面积
{
int area = a * b;
Console.WriteLine($"矩形面积:{area}");
}
public void Color() // 定义色彩
{
Console.WriteLine("矩形色彩:蓝色");
}
}
执行结果为:
矩形面积:50
矩形色彩:蓝色

【实例 10】一个接口 IFly 继承了 IBird 和 IAirplane 接口的应用,InfoFly 类将实现 IFly 接口的 PediaFly 抽象方法,以及它所继承的 IAirplane 接口的 AirplaneFly 抽象方法和 IBird 接口的 BirdFly 方法。
InfoFly infofly = new InfoFly();
infofly.BirdFly();
infofly.AirplaneFly();
infofly.PediaFly();
interface IBird // 定义接口 IBird
{
void BirdFly();
}
interface IAirplane // 定义接口 IAirplane
{
void AirplaneFly();
}
interface IFly : IBird, IAirplane // 接口IFly继承IBird和IAirplane
{
void PediaFly();
}
class InfoFly : IFly // 定义类 InfoFly 实作 IFly
{
public void BirdFly() // 实作 BirdFly
{
Console.WriteLine("鸟用翅膀飞");
}
public void AirplaneFly() // 实作 AirplaneFly
{
Console.WriteLine("飞机用引擎飞");
}
public void PediaFly() // 实作 PediaFly
{
Console.WriteLine("飞行百科");
}
}
执行结果为:
鸟用翅膀飞
飞机用引擎飞
飞行百科

C#虚拟接口方法
前面介绍的接口方法均是抽象方法,这些方法需要在继承的类内实现,C# 从 8.0 版本起支持虚拟接口方法,这个方法又称默认方法。虚拟接口方法可以有完整的实体内容,同时此方法不需要在类内实现。使用时需要留意,类并没有继承接口的虚拟接口方法,所以类对象无法调用虚拟接口方法。
【实例 11】虚拟方法的说明,这个程序的重点是类对象无法调用虚拟方法,所以第 9 行若是拿掉“//”会有错误产生。
IComputer com = new Software(); // Upcasting
com.Office();
com.Programming("OK");
com.Life();
Software soft = new Software(); // Software类的soft物件
soft.Office();
soft.Programming("OK");
//soft.Life(); // 编译错误
interface IComputer
{
void Office(); // 定义 Office
void Programming(string text); // 定义 Programming
void Life() // virtual 方法
{
Console.WriteLine("已经是生活必需品");
}
}
class Software : IComputer
{
public void Office() // 实作 Office
{
Console.WriteLine("适用一般职员");
}
public void Programming(string text) // 实作 Programming
{
Console.WriteLine("适用程序设计师");
}
}
执行结果为:
适用一般职员
适用程序设计师
已经是生活必需品
适用一般职员
适用程序设计师
ICP备案:
公安联网备案: