Files
My-Notes/笔记/CSharp/核心/接口.md
T
2026-06-21 09:51:55 +08:00

7.7 KiB
Raw Blame History

接口

概念: 接口使用 interface 关键字定义 它主要用来规定一组==能力 / 规则 / 契约==

简单理解: 接口不关心“你是谁” 只关心“你能不能做这件事”

例如: IFlyable 表示“会飞” 不管你是鸟、飞机还是飞行道具,只要实现了这个接口,就代表你拥有飞行能力

通常用法:

  1. 规定某些类必须实现哪些成员
  2. 表达一种能力,例如会飞、会攻击、可保存、可移动
  3. 让不同类型用同一套调用方式
  4. 弥补 C# 类只能单继承的问题,因为一个类可以实现多个接口
  5. 配合多态vob,让代码面向能力编程

语法

定义接口:

interface 接口名
{
	void 方法名();
}

实现接口:

class 类名 : 接口名
{
	public void 方法名()
	{

	}
}

命名习惯: 接口名通常以大写字母 I 开头 例如:IFlyableIAttackableISaveable


基础案例

interface IFlyable
{
	void Fly();
}

class Bird : IFlyable
{
	public void Fly()
	{
		Console.WriteLine("鸟在飞");
	}
}

class Plane : IFlyable
{
	public void Fly()
	{
		Console.WriteLine("飞机在飞");
	}
}

void LetItFly(IFlyable flyable)
{
	flyable.Fly();
}

LetItFly(new Bird());
LetItFly(new Plane());

理解:

  1. IFlyable 规定实现者必须有 Fly() 方法
  2. BirdPlane 类型不同,但都实现了 IFlyable
  3. LetItFly 不关心传进来的是鸟还是飞机,只关心它会不会飞

这就是接口常见用法: ==面向能力编程,而不是面向具体类型编程==


接口中的成员

常见接口成员:

interface IMovable
{
	void Move();
	int Speed { get; set; }
}

实现:

class Player : IMovable
{
	public int Speed { get; set; }

	public void Move()
	{
		Console.WriteLine("玩家移动");
	}
}

接口中常见成员包括:

  1. 方法
  2. 属性
  3. 索引器
  4. 事件

初学阶段重点先掌握: 接口方法 + 接口属性


接口成员默认是 public

接口里这样写:

interface IAttackable
{
	void Attack();
}

实现时必须写 public

class Enemy : IAttackable
{
	public void Attack()
	{
		Console.WriteLine("敌人攻击");
	}
}

错误写法:

class Enemy : IAttackable
{
	void Attack()
	{
	}
}

原因: 接口成员代表对外公开的契约 类实现接口时,成员访问级别不能比接口更低


一个类可以实现多个接口

C# 的类只能继承一个父类,但可以实现多个接口。

interface IMovable
{
	void Move();
}

interface IAttackable
{
	void Attack();
}

class Player : IMovable, IAttackable
{
	public void Move()
	{
		Console.WriteLine("玩家移动");
	}

	public void Attack()
	{
		Console.WriteLine("玩家攻击");
	}
}

理解: Player 同时拥有“可移动”和“可攻击”两种能力


继承类和实现接口同时存在

写法:

class 子类名 : 父类名, 接口1, 接口2
{

}

注意顺序: ==先写父类,再写接口==

案例:

class Character
{
	public string Name;
}

interface IAttackable
{
	void Attack();
}

class Warrior : Character, IAttackable
{
	public void Attack()
	{
		Console.WriteLine(Name + "挥剑攻击");
	}
}

错误示意:

// class Warrior : IAttackable, Character
// {
// }

如果既要继承类,又要实现接口,父类必须写在最前面。


接口也可以继承接口

接口之间可以继承,而且可以继承多个接口。

interface IMovable
{
	void Move();
}

interface IAttackable
{
	void Attack();
}

interface IPlayerAction : IMovable, IAttackable
{
	void UseItem();
}

实现 IPlayerAction 的类,必须实现:

  1. Move()
  2. Attack()
  3. UseItem()
class Player : IPlayerAction
{
	public void Move()
	{
	}

	public void Attack()
	{
	}

	public void UseItem()
	{
	}
}

接口引用和多态

接口也可以当变量类型使用。

IAttackable attacker = new Player();
attacker.Attack();

也可以作为方法参数:

void DoAttack(IAttackable attacker)
{
	attacker.Attack();
}

好处: 调用方只依赖 IAttackable 任何实现了这个接口的对象都能传进来

DoAttack(new Player());
DoAttack(new Enemy());

这也是多态的一种表现。


接口和里氏替换原则

接口常用来拆分能力,避免不合理继承。

比如:

abstract class Bird
{
	public string Name;
}

interface IFlyable
{
	void Fly();
}

class Sparrow : Bird, IFlyable
{
	public void Fly()
	{
		Console.WriteLine("麻雀飞");
	}
}

class Penguin : Bird
{
	public void Swim()
	{
		Console.WriteLine("企鹅游泳");
	}
}

这样:

  1. Bird 只表达“鸟”
  2. IFlyable 只表达“会飞”
  3. 不会飞的企鹅不用硬实现 Fly()

这个例子可以和里氏替换原则一起理解。


显式实现接口

当两个接口有同名方法,或者你不希望方法直接暴露在类对象上,可以显式实现接口。

interface IWalkable
{
	void Move();
}

interface IFlyable
{
	void Move();
}

class Bird : IWalkable, IFlyable
{
	void IWalkable.Move()
	{
		Console.WriteLine("鸟在走");
	}

	void IFlyable.Move()
	{
		Console.WriteLine("鸟在飞");
	}
}

Bird bird = new Bird();

IWalkable walkable = bird;
walkable.Move();

IFlyable flyable = bird;
flyable.Move();

注意: 显式实现接口时,不写 public 调用时通常要先把对象当成对应接口类型

初学阶段先知道有这个写法即可,最常用的还是普通实现接口。


常见错误

错误1:实现接口时忘记 public

class Player : IAttackable
{
	void Attack()
	{
	}
}

接口成员默认是公开契约,实现时通常要写 public


错误2:没有实现接口所有成员

interface IMovable
{
	void Move();
	int Speed { get; set; }
}

class Player : IMovable
{
	public void Move()
	{
	}
}

Speed 没实现,所以会报错。


错误3:把接口当成类直接创建对象

IFlyable flyable = new IFlyable();

接口只是规则,不能直接 new

正确写法:

IFlyable flyable = new Bird();

什么时候用接口

适合用接口的情况:

  1. 你要表达的是“能力”,不是“父子身份”
  2. 多个无关类型都有同一种行为
  3. 一个类型需要拥有多种能力
  4. 想让代码依赖规则,而不是依赖具体类

例如:

  • IFlyable:会飞
  • IAttackable:能攻击
  • ISaveable:可保存
  • IDamageable:可受伤

注意

  1. 接口用 interface 定义
  2. 接口名通常以 I 开头
  3. 接口不能直接创建对象
  4. 类和结构体都可以实现接口
  5. 一个类可以实现多个接口
  6. 接口成员实现时通常要写 public
  7. 接口更适合表达“能做什么”,抽象类更适合表达“是什么”
  8. 接口常和多态、里氏替换原则一起理解

一句话记忆

==接口是能力契约,谁实现它,谁就必须按规则提供这些能力。==

再压缩一点: ==接口管能不能做,不管你是谁。==


面试/复习时怎么说

可以这样答:

“接口是用 interface 定义的一组契约,主要用来规定实现类必须提供哪些成员。
类可以实现多个接口,所以接口常用来表达能力,比如可移动、可攻击、可保存。
调用方可以面向接口编程,只依赖能力规则,不依赖具体类,这样更利于扩展和多态。”


引用:

  1. Microsoft Learn: interface (C# Reference)
  2. Microsoft Learn: Interfaces

#接口 #核心