能否在C#中以泛型参数作为基类实现通用可比较类?
能不能在C#中实现
class A<TBase> : TBase {}? 首先直接给结论:不行,C#不支持让泛型类直接继承自类型参数TBase。
C#的泛型规则要求,泛型类的基类必须是一个具体的类型(比如object、自定义的基类),或者是带有明确约束的泛型类型(比如List<T>),但不能是无约束的类型参数——编译器无法提前验证TBase是否是合法的可继承类型(比如它可能是值类型、密封类,甚至接口),即使你给TBase加上class约束,也依然不允许这种写法。
针对你的核心需求:复用比较运算符的样板代码
你想要避免Height、Weight这类类重复编写大量比较运算符的逻辑,其实有更可行的替代方案,不需要依赖动态继承TBase:
方案1:抽象泛型基类(推荐)
创建一个实现了IComparable<T>和所有比较运算符的抽象基类,让需要比较的子类继承它,只需要实现核心的CompareTo方法即可:
public abstract class ComparableBase<T> : IComparable<T> where T : ComparableBase<T> // 约束T是当前基类的子类,确保类型安全 { // 核心抽象方法,子类必须实现具体的比较逻辑 public abstract int CompareTo(T other); // 复用的安全比较工具方法 private static int SafeCompare(T x, T y) { if (x is null) { return y is null ? 0 : -1; } return x.CompareTo(y); } // 重载所有比较运算符 public static bool operator <(T x, T y) => SafeCompare(x, y) < 0; public static bool operator <=(T x, T y) => SafeCompare(x, y) <= 0; public static bool operator >(T x, T y) => SafeCompare(x, y) > 0; public static bool operator >=(T x, T y) => SafeCompare(x, y) >= 0; public static bool operator ==(T x, T y) => SafeCompare(x, y) == 0; public static bool operator !=(T x, T y) => SafeCompare(x, y) != 0; // 重写Equals和GetHashCode,匹配==运算符的逻辑 public override bool Equals(object obj) { return obj is T other && CompareTo(other) == 0; } public override int GetHashCode() { // 子类应该重写这个方法,返回内部值的哈希码 return base.GetHashCode(); } }
然后你的Height类只需要这么写:
public class Height : ComparableBase<Height> { private int _heightInMillimeters; public Height(int millimeters) { _heightInMillimeters = millimeters; } // 只需要实现这一个方法,其他运算符自动继承 public override int CompareTo(Height other) { if (other is null) return 1; return _heightInMillimeters.CompareTo(other._heightInMillimeters); } // 重写GetHashCode,确保和Equals逻辑一致 public override int GetHashCode() { return _heightInMillimeters.GetHashCode(); } }
Weight类同理,只需要实现CompareTo和GetHashCode,所有比较运算符都不用重复编写了。
方案2:接口+扩展方法(适合已有基类的场景)
如果你的类已经有了其他基类,不能再继承ComparableBase<T>,可以用接口配合扩展方法复用核心比较逻辑:
// 定义标记接口,配合扩展方法 public interface ISelfComparable<T> : IComparable<T> where T : ISelfComparable<T> { } public static class ComparableExtensions { // 复用的安全比较方法 public static int SafeCompareTo<T>(this T x, T y) where T : ISelfComparable<T> { return x != null ? x.CompareTo(y) : (y != null ? -1 : 0); } }
然后子类实现接口,重载运算符时复用扩展方法:
public class Weight : SomeExistingBaseClass, ISelfComparable<Weight> { private double _weightInKilograms; public Weight(double kilograms) { _weightInKilograms = kilograms; } public int CompareTo(Weight other) { if (other is null) return 1; return _weightInKilograms.CompareTo(other._weightInKilograms); } // 运算符重载时复用扩展方法,减少重复代码 public static bool operator <(Weight x, Weight y) => x.SafeCompareTo(y) < 0; public static bool operator <=(Weight x, Weight y) => x.SafeCompareTo(y) <= 0; public static bool operator >(Weight x, Weight y) => x.SafeCompareTo(y) > 0; public static bool operator >=(Weight x, Weight y) => x.SafeCompareTo(y) >= 0; public static bool operator ==(Weight x, Weight y) => x.SafeCompareTo(y) == 0; public static bool operator !=(Weight x, Weight y) => x.SafeCompareTo(y) != 0; // 别忘了重写Equals和GetHashCode public override bool Equals(object obj) { return obj is Weight other && CompareTo(other) == 0; } public override int GetHashCode() { return _weightInKilograms.GetHashCode(); } }
内容的提问来源于stack exchange,提问作者Clinton
相关产品推荐
相关产品推荐

