Menu
CoddyTech

显式实现接口

本课属于 Coddy C# 学习旅程的“面向对象编程”单元。第 28 课,共 70 课。

当一个类实现多个接口,而这些接口包含同名成员时,就会出现命名冲突。显式接口实现可以让你为每个接口分别提供实现,从而解决这个问题。

显式实现时,你需要在成员名称前加上接口名称,并省略访问修饰符:

public interface IAmericanPlug
{
    void Connect();
}

public interface IEuropeanPlug
{
    void Connect();
}

public class UniversalAdapter : IAmericanPlug, IEuropeanPlug
{
    void IAmericanPlug.Connect()
    {
        Console.WriteLine("Connected to 120V");
    }
    
    void IEuropeanPlug.Connect()
    {
        Console.WriteLine("Connected to 220V");
    }
}

显式实现的成员只能通过接口类型的变量访问,不能直接通过类本身访问:

var adapter = new UniversalAdapter();
// adapter.Connect();  // 无法编译!

IAmericanPlug american = adapter;
american.Connect();  // 已连接到 120V

IEuropeanPlug european = adapter;
european.Connect();  // 已连接到 220V

当你想从类的公共 API 中隐藏接口成员时,这种技术也很有用。如果某个方法只有在将对象视为特定接口时才有意义,那么显式实现可以让类的表面保持简洁,同时仍然履行契约。

challenge icon

挑战

简单

我们来构建一个报表生成系统,演示显式接口实现如何让同一个类根据所使用的接口提供不同的行为。你将创建一个文档,使其在显示和打印时采用不同的格式。

你将把代码分成 4 个文件:

  • IDisplayable.cs:在 Reports 命名空间中定义一个名为 IDisplayable 的接口。这个接口表示可以在屏幕上显示的内容。它应声明一个返回字符串的 Render() 方法。
  • IPrintable.cs:在 Reports 命名空间中定义一个名为 IPrintable 的接口。这个接口表示可以发送到打印机的内容。它也应声明一个返回字符串的 Render() 方法。注意,这会与 IDisplayable 产生命名冲突!
  • Report.cs:在 Reports 命名空间中定义一个 Report 类,同时实现 IDisplayable 和 IPrintable。报表应具有 Title 属性(string)和 Content 属性(string),并通过构造函数设置这两个值。使用显式接口实现,让 Render() 提供不同的行为:
    • 用于显示时的渲染结果:"[SCREEN] {Title}: {Content}"
    • 用于打印时的渲染结果:"[PRINT] {Title} | {Content}"
  • Program.cs:在主文件中,使用输入值创建一个 Report。由于只能通过接口变量访问显式实现的方法,因此要将同一个报表分别存入 IDisplayable 变量和 IPrintable 变量,然后分别调用它们的 Render(),以展示同一个对象会根据你使用的接口产生不同的输出。

你将收到两个输入:

  • 报表标题
  • 报表内容

按以下格式输出:

Display version:
{Render() via IDisplayable}
Print version:
{Render() via IPrintable}

例如,如果输入是 Sales Report 和 Q4 revenue increased by 15%,输出应为:

Display version:
[SCREEN] Sales Report: Q4 revenue increased by 15%
Print version:
[PRINT] Sales Report | Q4 revenue increased by 15%

注意,同一个 Report 对象会根据你用来访问它的接口引用而表现出不同的行为。这就是显式接口实现的作用:解决命名冲突,同时提供符合使用场景的行为!

亲手试试

using System;
using Reports;

class Program
{
    public static void Main(string[] args)
    {
        // 读取输入
        string title = Console.ReadLine();
        string content = Console.ReadLine();

        // TODO: 用标题和内容创建一个 Report 对象

        // TODO: 将报告存入一个 IDisplayable 变量

        // TODO: 将同一份报告存入一个 IPrintable 变量

        // TODO: 调用 IDisplayable 的 Render(),输出显示版本
        Console.WriteLine("Display version:");
        // 在这里输出渲染结果

        // TODO: 调用 IPrintable 的 Render(),输出打印版本
        Console.WriteLine("Print version:");
        // 在这里输出渲染结果
    }
}
quiz icon自我测试

这节课包含一个小测验。开始学习即可作答,并记录你的进度。

面向对象编程中的所有课

自己练习: C# 在线编译器