如何让C#基类Add泛型方法获得指定枚举类型的自动提示
问题背景
问题说明
- 基类中定义了名为
Add的方法,该方法使用类的泛型类型供子类继承使用 - 该基类会被其他多个基类继承使用
- 双泛型参数基类
Base<T1,T2>和三泛型参数基类Base<T1,T2,T3>的核心逻辑一致,仅三泛型基类需要实现额外功能 Base<T1>中定义的Add方法需要同时供双泛型、三泛型基类的子类使用- 泛型参数T2是枚举类型
现存问题
Add方法的泛型参数无约束,可传入任意类型值- Visual Studio无法自动提示为T2指定的枚举类型,开发体验不佳
不可接受的解决方案
Add方法本身包含大量业务逻辑,以下方案会导致后续修改Add方法逻辑时需要同步修改所有继承类,维护成本过高,因此不予采纳:
- 将
Add方法复制粘贴到双泛型、三泛型基类中重复实现 - 在双泛型、三泛型基类中重写
Add方法,内部调用base.Add()实现
现有代码示例
#region For T type class Fruit { public string Name { get; set; } } enum Books { None = 0, Love } enum Sleeps { None = 0, Nightmare } enum Months { None = 0, October } #endregion #region Class to inherit abstract class Base<T1> { internal void Add<T2>(T2 t2) { } } abstract class Base<T1, T2> : Base<T1> where T2 : Enum { internal abstract T1 Where(int id); } abstract class Base<T1, T2, T3> : Base<T1, T2> where T2 : Enum where T3 : Enum { internal abstract T1 Where(int id, T3 t3); } #endregion #region Classes that can be used as objects. (Final) class A : Base<Fruit, Months> { public A() { Add(Months.October); Add(Sleeps.Nightmare); //X _ = Where(1); } internal override Fruit Where(int id) { throw new NotImplementedException(); } } class B : Base<Fruit, Books, Sleeps> { public B() { Add(Books.Love); Add(Months.October); //X _ = Where(1, Sleeps.Nightmare); _ = Where(1); //X } internal override Fruit Where(int id, Sleeps t3) { throw new NotImplementedException(); } internal override Fruit Where(int id) //X { throw new NotImplementedException(); } } #endregion
效果截图


解决方案
你可以通过将Add方法的泛型参数从方法级别上移到类级别,和子类定义的T2枚举绑定实现需求,无需重复实现Add逻辑,也不需要在子类重写方法。
如果当前没有直接继承Base<T1>的非枚举泛型子类,可以直接调整基类结构:
#region Class to inherit // 调整为带枚举约束的抽象基类 abstract class Base<T1, TEnum> where TEnum : Enum { // Add方法直接使用类级别的TEnum泛型,不再单独定义泛型参数 internal void Add(TEnum t2) { // 原有全部业务逻辑保留在此处,无需修改 } } // 双泛型基类继承时将T2作为TEnum传入父类 abstract class Base<T1, T2> : Base<T1, T2> where T2 : Enum { internal abstract T1 Where(int id); } // 三泛型基类继承时保持原有逻辑,T2自动传递给上层基类的TEnum abstract class Base<T1, T2, T3> : Base<T1, T2> where T2 : Enum where T3 : Enum { internal abstract T1 Where(int id, T3 t3); } #endregion
如果还有其他直接继承Base<T1>、不需要枚举约束的子类,可以额外加一层中间基类做兼容:
#region Class to inherit // 最上层基类保留,存放不需要枚举约束的通用逻辑 abstract class Base<T1> { // 原有其他通用方法放在此处 } // 新增带枚举约束的中间基类,仅用来实现Add方法 abstract class BaseWithEnum<T1, TEnum> : Base<T1> where TEnum : Enum { internal void Add(TEnum t2) { // 原有全部业务逻辑保留在此处 } } // 双泛型基类改为继承中间带枚举的基类 abstract class Base<T1, T2> : BaseWithEnum<T1, T2> where T2 : Enum { internal abstract T1 Where(int id); } // 三泛型基类继承逻辑不变 abstract class Base<T1, T2, T3> : Base<T1, T2> where T2 : Enum where T3 : Enum { internal abstract T1 Where(int id, T3 t3); } #endregion
修改后效果完全符合预期:
Add方法的参数类型自动绑定子类继承时指定的T2枚举类型,传入其他枚举/类型时编译直接报错- Visual Studio可以自动提示对应枚举的可选值,开发体验符合要求
Add的业务逻辑仅在最上层基类实现一次,后续迭代修改不需要同步调整任何子类,维护成本为0
内容的提问来源于stack exchange,提问作者Emre
相关产品推荐
相关产品推荐

