C#泛型接口中能否移除指代实现类的TImpl泛型参数以简化代码?
是否可以直接移除TImpl泛型参数
不可以,你现在用的是C#实现奇异递归模板模式(CRTP) 的标准写法,看似冗余的TImpl : Base<TImpl, T1>约束,核心作用是在编译期强制Build方法的入参必须是当前接口的实现类本身,而非其他同接口的实现类,保障类型安全。
如果强行移除TImpl,你只能把接口定义成如下形式:
public interface IBase<T1> { T1 Build(IBase<T1> arg); }
对应的实现类必须对入参做强转,运行时存在类型转换失败的风险,完全丢失了原来的类型安全特性:
public class Impl1 : IBase<int> { public int Value { get; set; } public int Build(IBase<int> arg) { // 存在非Impl1类型的入参传入时抛出转换异常的风险 return ((Impl1)arg).Value; } }
有没有简化写法
你想要的public TImpl.C1 Method(TImpl arg)语法,C#目前没有原生支持的“直接提取实现类成员类型”的特性,不过可以根据需求选择不同的简化方案:
- 如果只是觉得每次声明继承时写全泛型参数麻烦,可以在文件头部用类型别名简化重复声明:
// 文件头部定义别名 using Impl1Base = Base<Impl1, int>; using Impl2Base = Base<Impl2, string>; public class Impl1 : Impl1Base { public int Value { get; set; } public int Build(Impl1 arg) => arg.Value; }
- 如果使用C# 11及以上版本,可以用接口静态抽象成员结合全局类型别名进一步简化,不过核心的奇异递归模板模式(CRTP) 约束仍然无法完全省略,这是C#泛型系统的设计限制,本身是为了保障类型安全做的强制要求。
- 如果你不需要在接口层面强校验
Build方法入参的精确类型,也可以放弃泛型约束,用动态类型实现,但会丢失编译期类型检查,不推荐生产环境使用。 - T1泛型参数无法省略,C#不支持泛型接口从实现类自动推导返回值类型,除非你用
object作为返回值类型,损失类型安全和性能。
内容的提问来源于stack exchange,提问作者Romulus Urakagi Ts'ai
相关产品推荐
相关产品推荐

