基于接口开发插件时如何调用对象内部实现且不暴露给插件
可行实现方案推荐
方案1:职责拆分(优先推荐)
这是最符合单一职责原则的实现方式,将用户操作逻辑从用户实体中剥离,统一放到用户管理器中,通过接口隔离区分公共访问能力和内部访问能力,完全消除类型转换需求。
实现逻辑:
- 定义两套接口:公共接口对插件可见,仅包含插件需要的成员;内部接口对主程序集可见,继承公共接口,补充内部需要的操作方法。
- 内部组件依赖内部接口,插件仅依赖公共接口。
代码示例:
// 公共接口,对插件程序集可见 public interface IUserManager { IReadOnlyCollection<IUser> Users { get; } } // 内部接口,仅主程序集可见 internal interface IUserManagerInternal : IUserManager { void DeleteUser(IUser user); void DeleteAllUsers(); } public interface IUser { string Name { get; } } class UserImpl : IUser { public string Name { get; } // 仅保留实体属性,操作逻辑移到管理器 } class UserManager : IUserManagerInternal { public IReadOnlyCollection<IUser> Users { get; } public void DeleteAllUsers() { foreach(var user in Users) { DeleteUser(user); } } public void DeleteUser(IUser user) { if (user is not UserImpl impl) throw new ArgumentException("无效用户实例", nameof(user)); // 执行删除逻辑 } } // 内部组件依赖内部接口 class NetworkController { private readonly IUserManagerInternal _userManager; public void ReceiveDeleteMessage(string name) { var user = _userManager.Users.Single(x => x.Name == name); _userManager.DeleteUser(user); // 无需类型转换,直接调用 } } // 插件仅依赖公共接口 class Plugin { public Plugin(IUserManager userManager) { Console.WriteLine(userManager.Users.First().Name); // 完全接触不到删除相关能力 } }
该方案无类型转换开销,接口边界清晰,单元测试时直接mock对应接口即可,无需额外配置。
方案2:internal方法 + 单元测试可见配置
适合不想调整现有代码结构的小型项目,直接通过访问修饰符控制方法可见性:
- 将
UserImpl的Delete方法访问修饰符从public改为internal - 在主程序集的配置文件中添加
[assembly: InternalsVisibleTo("你的单元测试项目名")],允许单元测试项目访问internal成员
插件程序集未被授予internal访问权限,就算拿到UserImpl实例也无法调用Delete方法,主程序集内部可直接调用该方法。
方案3:internal内部接口 + 显式接口实现
如果你希望保留实体上的操作方法,可以对原有内部接口方案做优化,彻底避免接口泄露:
- 给
IInternalUser添加internal修饰符,插件程序集完全看不到该接口类型 - 显式实现
IInternalUser的Delete方法,仅当实例被转换为IInternalUser类型时才能访问该方法
代码示例:
// 内部接口,仅主程序集可见 internal interface IInternalUser : IUser { void Delete(); } class UserImpl : IInternalUser { public string Name { get; } // 显式实现接口 void IInternalUser.Delete() { // 执行删除逻辑 } } // 内部调用示例 if(user is IInternalUser internalUser) { internalUser.Delete(); }
该方案下插件完全没有途径访问到Delete方法,类型转换仅存在于主程序集内部,可控性高。
内容的提问来源于stack exchange,提问作者Romain
相关产品推荐
相关产品推荐

