如何简化C#中带泛型约束的IBar与ISystem泛型类型声明?
简化C#泛型接口的实现方案
针对泛型接口参数过多的问题,我们可以利用C# 7.3及以上版本支持的开放构造类型约束来简化声明,同时完整保留所有类型约束的有效性。
第一步:简化IBar接口
把IBar<TFoo, TId, TIndex>简化为IBar<TFoo, TIndex>,同时保持TFoo必须继承IFoo<TId>的约束。这里不需要把TId作为IBar的显式参数——因为TFoo本身已经实现了IFoo<TId>,编译器能从TFoo的具体类型自动推断出TId。修改后的代码如下:
// 保留原IFoo接口不变 public interface IFoo<TId> { TId Id { get; set; } } // 简化后的IBar:移除TId参数,用开放构造类型约束确保TFoo是IFoo的泛型实现 public interface IBar<TFoo, TIndex> where TFoo : IFoo<> { TFoo First { get; set; } TFoo Second { get; set; } TIndex Index { get; set; } }
第二步:简化ISystem接口
把ISystem<TFoo, TBar, TId, TIndex>简化为ISystem<TFoo, TBar>,通过约束让编译器自动推断TId和TIndex。同时修正原始代码中的错误:接口成员不能使用private修饰符,因此要去掉private set。修改后的代码如下:
// 简化后的ISystem:移除TId和TIndex参数,通过约束自动推断类型 public interface ISystem<TFoo, TBar> where TFoo : IFoo<> where TBar : IBar<TFoo,> { ICollection<TFoo> Foos { get; } ICollection<TBar> Bars { get; } int CalculateSomething(TFoo foo); }
验证实现类
现在实现类只需要指定具体的Foo和Bar类型,无需显式声明TId和TIndex,编译器会自动推断,且能正常访问所有强类型成员:
// 具体的Foo实现,TId为Guid public class Foo : IFoo<Guid> { public Guid Id { get; set; } } // 具体的Bar实现,TFoo为Foo,TIndex为DateTimeOffset public class Bar : IBar<Foo, DateTimeOffset> { public Foo First { get; set; } public Foo Second { get; set; } public DateTimeOffset Index { get; set; } } // 实现ISystem,只需指定Foo和Bar public class MockSystem : ISystem<Foo, Bar> { public ICollection<Foo> Foos { get; } = new List<Foo>(); public ICollection<Bar> Bars { get; } = new List<Bar>(); public int CalculateSomething(Foo foo) { // 正常访问foo.Id(类型为Guid) return foo.Id.ToString().Length; } public void AccessBarIndex(Bar bar) { // 正常访问bar.Index(类型为DateTimeOffset) var indexValue = bar.Index; } }
关键说明
- 开放构造类型约束(如
IFoo<>、IBar<TFoo,>)是C# 7.3引入的特性,用于约束泛型类型必须是某个泛型接口/类的任意泛型实现; - 通过这种方式,我们不需要在高层接口中重复声明底层已经包含的类型参数,编译器会自动从具体实现类中推断出对应的类型;
- 所有原有的类型约束都被保留,不会破坏类型安全性。
内容的提问来源于stack exchange,提问作者InstilledBee
相关产品推荐
相关产品推荐

