C# SDK命令模式优化:规避请求执行方法直接调用的方案咨询
解决方案:泛型约束+内部接口隔离
针对你的问题,核心是要隔离命令的执行入口,同时让执行器能直接处理具体命令类型,避免冗余和类型转换。下面是一套贴合C#特性的实现方案:
核心思路
- 用内部可见性接口封装命令的执行逻辑,对外隐藏
Execute方法,强制外部只能通过SDK统一入口调用。 - 用泛型约束让执行器直接绑定具体命令类型,无需类型转换或分支判断。
- 拆分公共属性与执行逻辑,既保证外部能正常设置命令参数,又能保护执行流程不被绕过。
代码实现
1. 定义隔离层接口与基类
// 仅SDK内部可见的命令执行接口,对外完全隐藏 internal interface IInternalCommand { void Validate(); void Execute(); } // 对外暴露的命令基类,仅包含公共参数属性 public abstract class CommandBase { // 示例公共参数:所有命令共享的请求ID public Guid RequestId { get; init; } = Guid.NewGuid(); }
2. 实现具体命令
每个命令继承公共基类并实现内部执行接口,外部无法直接访问Validate和Execute:
public class CreateUserCommand : CommandBase, IInternalCommand { // 对外可见的业务参数 public string Username { get; init; } public string Email { get; init; } // 仅SDK内部可调用的校验逻辑 void IInternalCommand.Validate() { if (string.IsNullOrWhiteSpace(Username)) throw new ArgumentException("用户名不能为空"); if (!Email.Contains("@")) throw new ArgumentException("邮箱格式不合法"); } // 仅SDK内部可调用的执行逻辑 void IInternalCommand.Execute() { // 具体业务操作:比如写入数据库、调用服务等 Console.WriteLine($"创建用户:{Username}(邮箱:{Email})"); } } public class DeleteUserCommand : CommandBase, IInternalCommand { public Guid UserId { get; init; } void IInternalCommand.Validate() { if (UserId == Guid.Empty) throw new ArgumentException("用户ID不能为空"); } void IInternalCommand.Execute() { Console.WriteLine($"删除用户:{UserId}"); } }
3. 泛型命令执行器
通过泛型约束直接绑定具体命令类型,无需转换,逻辑清晰无冗余:
internal class CommandExecutor<TCommand> where TCommand : CommandBase, IInternalCommand { public void Run(TCommand command) { // 调用命令自身的校验 (command as IInternalCommand).Validate(); // 执行命令逻辑 (command as IInternalCommand).Execute(); } }
4. SDK统一入口
对外暴露唯一执行入口,在这里做全局校验(比如权限、请求合法性),然后分发到对应执行器:
public static class SdkCommandRunner { public static void Execute<TCommand>(TCommand command) where TCommand : CommandBase, IInternalCommand { // 全局统一校验:比如请求ID合法性、SDK权限校验等 if (command.RequestId == Guid.Empty) throw new InvalidOperationException("请求ID不能为空"); // 直接用泛型执行器处理,无需分支或反射 var executor = new CommandExecutor<TCommand>(); executor.Run(command); } }
外部调用示例
外部代码只能通过SDK入口执行命令,无法直接访问命令的Execute方法:
// 创建命令并设置参数 var createCmd = new CreateUserCommand { Username = "zhangsan", Email = "zhangsan@example.com" }; // 必须通过SDK入口执行,无法直接调用createCmd.Execute() SdkCommandRunner.Execute(createCmd); var deleteCmd = new DeleteUserCommand { UserId = Guid.NewGuid() }; SdkCommandRunner.Execute(deleteCmd);
方案优势
- 彻底防止误用:
Execute方法被内部接口隐藏,外部代码无法绕过SDK入口直接调用。 - 无冗余/类型转换:泛型执行器直接绑定具体命令类型,全程不需要强制转换或分支判断。
- 扩展性强:新增命令时只需继承
CommandBase并实现IInternalCommand,无需修改现有执行器或入口代码。 - 职责清晰:全局校验在入口处理,命令专属校验在命令内部实现,执行逻辑与参数分离。
内容的提问来源于stack exchange,提问作者mulllhausen
相关产品推荐
相关产品推荐

