====== C# 接口 (Interface) 深度解析 ======
接口(Interface)是 C# 面向对象编程中非常核心的概念。它定义了“行为的规范”,起到了强制契约的作用。
===== 1. 接口简介 =====
**关键字**:%%interface%% (读音: /'ɪntəfeɪs/)
接口定义了所有类继承接口时应遵循的**语法合同**。接口定义了“**是什么**”(规范),而不关心“**怎么做**”(实现)。
==== 核心特性 ====
* **纯粹的规范**:接口本身通常不包含实现逻辑(C# 8.0+ 除外),它只规定了类或结构体必须具备的成员(方法、属性、事件、索引器)。
* **强制实现**:一旦一个类继承了某个接口,它**必须**实现该接口中定义的所有成员,否则编译器会报错。
* **引用类型**:接口是引用类型。虽然不能直接实例化接口(不能 `new Interface()`),但可以声明接口类型的变量,用于指向实现了该接口的类的实例(多态)。
* **访问修饰符**:接口中的成员默认是 **public** 的。在旧版本 C# 中不允许显式添加修饰符;虽然新版本允许,但通常保持默认。
* **多继承**:C# 的类只能继承一个父类(单继承),但**可以实现多个接口**。这是接口最强大的功能之一。
* **层级关系**:接口可以继承其他接口,形成接口链。
**记忆口诀**:接口像是一个“职位描述(JD)”,类像是“员工”。JD 规定了员工必须会做什么(比如会编程、会英语),但具体怎么编程、怎么说英语,由员工(类)自己决定。
===== 2. 基础语法与多态 =====
为了实现多态(Polymorphism),我们通常使用**接口类型的变量**来引用**子类的对象**。
class Program
{
static void Main(string[] args)
{
// 多态的核心:左边是接口,右边是具体实现类
// IAnimal myDog = new IAnimal(); // 错误!接口不能被实例化
IAnimal myDog = new Dog();
// 调用接口的方法,实际执行的是 Dog 类中具体的实现
myDog.MakeSound(); // 输出 "Woof!"
}
}
// 1. 定义接口 (通常以 I 开头命名)
interface IAnimal
{
void MakeSound(); // 只有声明,没有方法体
}
// 2. 实现接口
class Dog : IAnimal
{
// 必须实现接口中的所有方法,且必须是 public
public void MakeSound()
{
Console.WriteLine("Woof! Im a Dog!");
}
}
===== 3. 接口成员:属性与方法 =====
接口不仅可以定义方法,还可以定义属性。
**注意**:在你提供的示例中,`Main` 函数尝试给属性赋值,但接口定义中只有 `get`。为了让代码能运行,下面的示例修正了 `set` 访问器。
class Program
{
static void Main(string[] args)
{
// 实例化实现类
ClassGetInformation syong = new ClassGetInformation();
// 使用属性
syong.Name = "智能手机";
syong.Code = "00254";
// 调用方法
syong.ShowInfo();
}
}
// 定义接口
interface IInformation
{
// 接口中的属性通常指明需要 get 还是 set
string Code { get; set; }
string Name { get; set; }
void ShowInfo();
}
// 自定义类实现接口
public class ClassGetInformation : IInformation
{
// 私有字段
private string _code = "";
private string _name = "";
// 实现接口属性 Code
public string Code
{
get { return _code; }
set { _code = value; }
}
// 实现接口属性 Name
public string Name
{
get { return _name; }
set { _name = value; }
}
// 实现接口方法
public void ShowInfo()
{
Console.WriteLine($"设备名称: {Name}, 编号: {Code}");
}
}
===== 4. 接口的多态性 (进阶举例) =====
这是接口最常见的应用场景:**统一管理不同的对象**。
using System;
class Program
{
static void Main(string[] args)
{
// 使用接口数组或集合,可以同时管理 Dog 和 Cat
IAnimal[] animals = new IAnimal[2];
animals[0] = new Dog();
animals[1] = new Cat();
// 遍历集合,虽然都是 IAnimal 类型,但表现出不同的行为
foreach (var animal in animals)
{
animal.MakeSound();
}
// 输出:
// I am a Dog!
// I am a Cat!
}
}
interface IAnimal
{
void MakeSound();
}
class Dog : IAnimal
{
public void MakeSound()
{
Console.WriteLine("I am a Dog!");
}
}
class Cat : IAnimal
{
public void MakeSound()
{
Console.WriteLine("I am a Cat!");
}
}
===== 5. 接口 vs 抽象类 =====
虽然它们都不能实例化,且都被用于被继承,但它们的设计目的不同。
^ 特性 ^ 接口 (Interface) ^ 抽象类 (Abstract Class) ^
| **继承数量** | **多继承** (一个类可实现多个接口) | **单继承** (一个类只能继承一个抽象类) |
| **成员实现** | 主要是规范,通常无代码实现 (C# 8.0前) | 可以包含已实现的具体方法,也可以包含抽象方法 |
| **字段 (Fields)** | 不能包含字段 (变量) | 可以包含字段、常量、静态成员 |
| **访问修饰符** | 默认为 public | 可以是 public, protected, private 等 |
| **设计理念** | **"Can Do"** (行为):像是一个插件,赋予类某种能力 (如 IDisposable, IEnumerable) | **"Is A"** (本质):定义类的族谱,提取子类的共性 |
===== 6. 知识拓展:密封类 (Sealed Class) =====
在面向对象设计中,如果说接口是**为了被继承**而生,那么密封类就是**禁止被继承**。
**关键字**:%%sealed%%
==== 为什么要用密封类? ====
- **安全性**:防止其他开发者随意继承你的类并重写关键功能,导致逻辑破坏。
- **性能优化**:编译器知道该类不会有子类,可以进行特定的底层优化(如把虚方法调用转换为直接调用)。
==== 语法示例 ====
// 定义一个密封类
sealed class FinalClass
{
public int Add(int a, int b)
{
return a + b;
}
}
// 错误!无法从密封类继承
// class TryToInherit : FinalClass
// {
// }
class Program
{
static void Main()
{
FinalClass fc = new FinalClass(); // 密封类可以被实例化
Console.WriteLine(fc.Add(1, 2));
}
}
**注意**:
* 接口 **不能** 是 sealed 的(因为接口必须被继承才有意义)。
* 抽象类 **不能** 是 sealed 的(因为抽象类必须被继承才能实现其抽象方法)。