====== 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 的(因为抽象类必须被继承才能实现其抽象方法)。