<p>C# 中没有 provides 关键字;它不属于 C# 语法,常见于 Kotlin 或 Java 模块系统。C# 实现接口提供语义靠 interface + internal 实现类 + DI 注册三要素协同。</p>

在 C# 中,没有 provides 关键字。该关键字不属于 C# 语言语法,既不出现在官方文档(Microsoft Learn)、C# 语言规范,也不被 Roslyn 编译器识别。你可能混淆了其他语言(如 Kotlin 的 provides 在某些 DI 框架 DSL 中出现,或 Java 模块系统的 provides … with … 声明)或误记了 C# 中的关键字。
真正起作用的是 interface + class + 依赖注入模式
面向接口编程中实现“实现类隐匿”与“变量安全”,靠的不是某个 magic 关键字,而是三要素协同:
-
定义清晰的接口:只暴露契约,不暴露实现细节。例如:
public interface IEmailService { void Send(string to, string subject); } -
具体实现类使用 internal 或 private 访问修饰符:避免外部程序集直接 new 或引用它。
internal class SmtpEmailService : IEmailService { ... } -
通过工厂、DI 容器或返回接口类型的构造方法注入依赖:调用方只持有
IEmailService,完全不知道背后是 Smtp 还是 Mock 实现。
典型安全实践:隐藏实现 + 控制变量生命周期
以 ASP.NET Core 为例,推荐做法如下:
- 在
Program.cs中注册为 scoped/service:services.AddScoped<IEmailService, SmtpEmailService>();—— 外部代码无法 newSmtpEmailService,只能通过 DI 获取接口实例 - 业务类中只声明接口类型字段:
private readonly IEmailService _email;,而非具体类型。这保证了变量不可被强制转型或访问私有成员 - 若需进一步限制访问,可将实现类放在独立的 internal-only 程序集,并仅导出接口(.NET 6+ 支持
InternalsVisibleTo精准授权)
替代“provides”的等效表达方式
如果你想要类似 “这个模块提供某接口实现” 的语义,C# 中的惯用写法是:
- 在扩展方法中封装创建逻辑:
public static IServiceCollection AddEmailService(this IServiceCollection services) { ... } - 用 XML 文档注释说明:
/// <summary>Provides an SMTP-based implementation of <see cref="IEmailService"/>.</summary> - 在模块初始化类中标注特性(自定义 Attribute),配合源生成器在编译期校验提供关系(高级场景)
不复杂但容易忽略:真正的隐匿不靠关键字,而靠访问控制 + 依赖倒置 + 构建时隔离。


















