C#接口的定义与使用

第1章 接口(interface)是什么

1.1 定义

• 接口是一组"能力"或"契约"的抽象描述,只规定"能做什么",不规定"怎么做"。

• 在 C# 中,接口是一种完全抽象的类型(fully abstract type)。

• 关键词:interface。

• 命名规范:以大写字母 I 开头,如 ILogger、IDisposable。

1.2 语法骨架
cs 复制代码
public interface 接口名
{
    // 1. 属性
    数据类型 属性名 { get; set; }   // 自动属性写法
    // 2. 方法
    返回类型 方法名(参数列表);
    // 3. 索引器
    数据类型 this[int index] { get; set; }
    // 4. 事件
    event EventHandler 事件名;
}

• 成员默认 public,不允许显式写 public/private/protected。

• 不允许有字段(field) 和 实例构造函数。

第2章 实现接口的三种姿势

2.1 隐式实现(Implicit Implementation)
cs 复制代码
public class FileLogger : ILogger
{
    public void Log(string message) => Console.WriteLine($"[File] {message}");
}

• 类中 public 成员签名与接口成员一致即可。

• 通过类变量或接口变量都能调用。

2.2 显式实现(Explicit Implementation)
cs 复制代码
public class DbLogger : ILogger
{
    void ILogger.Log(string message)   // 无访问修饰符
        => Console.WriteLine($"[DB] {message}");
}

• 只能"接口变量"调用:ILogger log = new DbLogger(); log.Log(...)

• 解决"菱形继承"时成员命名冲突。

2.3 结构体实现接口

cs 复制代码
public struct Point : IEquatable<Point>
{
    public int X, Y;
    public bool Equals(Point other) => X == other.X && Y == other.Y;
}

• 值类型也可实现接口,但注意装箱问题。

第3章 接口的进阶特性

cs 复制代码
interface IRunnable { void Run(); }
interface ILogger   { void Log(string msg); }

class Job : IRunnable, ILogger
{
    public void Run() => Log("Job is running");
    public void Log(string msg) => Console.WriteLine(msg);
}
3.2 接口继承接口
cs 复制代码
interface IAdvancedLogger : ILogger
{
    void LogError(Exception ex);
}

实现类必须实现全部成员(包括继承链)。

3.3 默认实现(C# 8.0+)
cs 复制代码
public interface ILogger
{
    void Log(string message);
    void LogError(Exception ex) => Log($"Error: {ex.Message}");
}

• 实现类不强制实现 LogError。

• 解决"接口演化"问题,向后兼容。

3.4 静态抽象成员(C# 11+)
cs 复制代码
public interface IFactory<T> where T : new()
{
    static abstract T Create();
}

用于泛型数学、泛型工厂等高级场景。

第4章 完整案例:插件式日志系统

4.1 需求

• 系统同时支持控制台、文件、数据库三种日志输出。

• 可随时插拔新的日志方式。

• 调用端面向接口编程,不依赖具体实现。

4.2 设计
  1. 定义接口 ILogger

  2. 三种实现:ConsoleLogger、FileLogger、SqlLogger

  3. 使用"工厂 + 反射"做插件加载

  4. 客户端仅依赖 ILogger

4.3 代码实现

(1) 接口:

cs 复制代码
public interface ILogger
{
    void Log(string message);
    void LogError(Exception ex);
}

(2) 控制台实现:

cs 复制代码
public class ConsoleLogger : ILogger
{
    public void Log(string message) => Console.WriteLine($"[Console] {DateTime.Now}: {message}");
    public void LogError(Exception ex) => Log($"ERROR: {ex}");
}

(3) 文件实现:

cs 复制代码
public class FileLogger : ILogger
{
    private readonly string _path;
    public FileLogger(string path) => _path = path;

    public void Log(string message)
        => File.AppendAllText(_path, $"{DateTime.Now}: {message}\n");

    public void LogError(Exception ex) => Log($"ERROR: {ex}");
}

(4) 工厂(简化版):

cs 复制代码
public static class LoggerFactory
{
    public static ILogger Create(string type, params object[] args)
    {
        var t = Type.GetType(type, true);
        return (ILogger)Activator.CreateInstance(t, args);
    }
}

(5) 配置文件 appsettings.json

cs 复制代码
{
  "Logger": {
    "Type": "FileLogger",
    "Args": [ "app.log" ]
  }
}

(6) LoggerConfig 的定义

cs 复制代码
// 通常放在 Models 文件夹或 Config 文件夹下
public class LoggerConfig
{
    // 对应 JSON 里的 "Type"
    public string Type { get; set; }

    // 对应 JSON 里的 "Args",由于 JSON 里是数组,所以用 object[]
    public object[] Args { get; set; } = Array.Empty<object>();
}

(7) 客户端:

cs 复制代码
var config = JsonSerializer.Deserialize<LoggerConfig>(File.ReadAllText("appsettings.json"));
ILogger logger = LoggerFactory.Create(config.Type, config.Args);

logger.Log("系统启动");
try { int x = 0, y = 1 / x; }
catch (Exception ex) { logger.LogError(ex); }

• 更换日志方式只需改配置,无需改业务代码。

第5章 常见误区与最佳实践

  1. 接口 vs 抽象类

    • 接口:多继承、纯契约、无状态。

    • 抽象类:单继承、可包含状态、可含实现。

  2. 接口隔离原则(ISP)

    • 不要强迫客户依赖它们不用的方法。

    • 把"胖接口"拆分为多个小接口。

  3. 命名规范

    • 接口以 I 开头,实现类以接口名去掉 I 为后缀,如 SqlLogger : ILogger。

  4. 显式实现的代价

    • 调用方必须转换成接口类型,降低可读性;除非解决冲突,否则优先隐式实现。

相关推荐
l1t5 分钟前
修改DeepSeek翻译得不对的V语言字符串文本排序程序
c语言·开发语言·python·v语言
z樾14 分钟前
Sum-rate计算
开发语言·python·深度学习
钮钴禄·爱因斯晨28 分钟前
赛博算命之八字测算事业运势的Java实现(四柱、五行、十神、流年、格局详细测算)
java·开发语言·aigc
_extraordinary_1 小时前
Java Map和Set
java·开发语言
jingjing~1 小时前
【Qt】QTime::toString(“hh:mm:ss.zzz“) 显示乱码的原因与解决方案
java·开发语言·qt
励志成为糕手1 小时前
深入剖析Spring IOC容器——原理、源码与实践全解析
java·开发语言·spring
杨DaB3 小时前
【SpringMVC】拦截器,实现小型登录验证
java·开发语言·后端·servlet·mvc
近津薪荼3 小时前
c++详解(宏与内联函数,nullptr)
开发语言·c++
R-G-B5 小时前
【12】大恒相机SDK C#开发 ——多相机开发,枚举所有相机,并按配置文件中的相机顺序 将所有相机加入设备列表,以便于对每个指定的相机操作
c#·大恒相机sdk·大恒多相机开发·大恒多相机枚举·大恒多相机指定顺序
R-G-B5 小时前
【13】大恒相机SDK C#开发 —— Fom1中实时处理的8个图像 实时显示在Form2界面的 pictureBox中
c#·大恒相机sdk·图像实时显示在另一个界面