C# 10.0自引用泛型变量声明及实现简化疑问
关于自引用泛型IBuilder的两个问题解答
问题1:当前实现是否过于复杂,有无更简洁的实现方式?
自引用泛型是实现强类型Fluent API的常规手段,但如果觉得这种写法冗余,可以根据场景选择以下简化方案:
方案1:放弃强类型自引用,使用非泛型接口
如果你的Builder体系不需要在子类扩展专属的Fluent方法,完全可以去掉泛型约束,直接返回接口本身:
public interface IContextBuilder { IContextBuilder WithName(string name); IContextBuilder WithTimeout(int seconds); IContext Build(); } public class DefaultContextBuilder : IContextBuilder { private readonly IContext _context = new Context(); public IContextBuilder WithName(string name) { _context.Name = name; return this; } public IContextBuilder WithTimeout(int seconds) { _context.Timeout = seconds; return this; } public IContext Build() => _context; }
这种写法最简洁,但缺点是链式调用时只能访问接口定义的方法,无法直接调用子类新增的扩展方法。
方案2:用抽象基类封装通用逻辑
如果需要保留强类型链式调用,同时减少重复代码,可以把泛型约束和通用逻辑抽到抽象基类中:
public abstract class ContextBuilderBase<TContext, TSelf> where TSelf : ContextBuilderBase<TContext, TSelf> where TContext : IContext, new() { protected readonly TContext _context = new TContext(); public abstract TSelf WithName(string name); public abstract TSelf WithTimeout(int seconds); public TContext Build() => _context; } public class DefaultContextBuilder : ContextBuilderBase<Context, DefaultContextBuilder> { public override DefaultContextBuilder WithName(string name) { _context.Name = name; return this; } public override DefaultContextBuilder WithTimeout(int seconds) { _context.Timeout = seconds; return this; } }
基类负责初始化Context和定义Build方法,子类只需要实现具体的Fluent配置方法,比纯接口的自引用写法更简洁,同时保留了强类型的链式调用能力。
问题2:如何声明IContextBuilder<IContext, IContextBuilder<...>>类型的变量?
这种递归泛型的声明不需要无限嵌套,直接用具体的实现类作为泛型参数即可:
// 直接声明为具体实现类对应的接口类型 IContextBuilder<IContext, DefaultContextBuilder> builder = new DefaultContextBuilder();
因为DefaultContextBuilder实现了IContextBuilder<IContext, DefaultContextBuilder>,所以这个声明是合法的,同时保留了接口的抽象性。
如果使用C# 12及以上版本,还可以通过泛型别名简化声明:
// 定义别名 using IDefaultContextBuilder = IContextBuilder<IContext, DefaultContextBuilder>; // 使用别名声明变量 IDefaultContextBuilder builder = new DefaultContextBuilder();
如果不想依赖具体实现类,建议回到问题1的方案1,使用非泛型接口声明变量,写法更简洁:
IContextBuilder builder = new DefaultContextBuilder();
内容的提问来源于stack exchange,提问作者Ruafel
相关产品推荐
相关产品推荐

