有没有一种方法可以重构这个 Generic class 来避免我的 C# 代码中的 where 约束?

Is there a way I can refactor this Generic class to avoid where constraints all over my C# code?

我目前有一个泛型接口和一个泛型类型,分别是 ISignal<T>SignalValue<T>。但是,我对 SignalValue 的 <T> 有一个约束,要求 T 具有可比性。

每一个的简化版本如下:

public interface ISignal<T> where T : IComparable
{
    string FullName { get; }
    public void SetValue(SignalValue<T> value, bool withLog = true);
    public SignalValue<T> GetValue(int readDelayMs = 500);
}

public class SignalValue<T> : IEquatable<T>, IComparable<T>, IComparable, ISignalValue where T : IComparable
{
    public readonly T Value;

    public SignalValue(T value)
    {
        Value = value;
    }

    public virtual int CompareTo(T other)
    {
       return Value.CompareTo(other);
    }
}

SignalValue<T> 主要用作值的包装器,其中 T 是 bool 或 double,并带有一些附加属性。但是,一旦我有了这个约束,我就会发现由于装箱,约束会到处传播。例如,我有以下静态方法,它显然也需要约束,即使它对任何比较相关的东西都没有真正的依赖性:

public static void DoSequence<T>(ISignal<T> signal, List<SequencePair<T>> pair) where T : IComparable
{
      if (signal == null) throw new ArgumentNullException(nameof(signal));
      if (pair == null) throw new ArgumentNullException(nameof(pair));
            
      if (pair.Count <= 0) return;

       List<SequencePair<T>> orderedList = pair.OrderBy(p => p.Seconds).ToList();
       //... more stuff but no comparison at all
 }

我明白为什么需要这个约束,但这也让我想知道在我的 class 中设置泛型约束是否是一种代码味道。有什么方法可以使我的 class 需要可比较的类型,而无需在我的代码中使用 SignalValue<T> 的任何地方进行约束?

在大多数情况下,通用约束可以通过委托给其他类型来代替。对于 IComparer<T> 的比较。所以如果你的方法需要比较,你可以添加一个 IComparer 参数。为了方便起见,您还可以添加具有泛型约束的重载,并使用 Comparer<T>.Default 并将实现委托给 main 方法。

大多数与排序相关的方法都可以采用 IComparer 对象,这通常是比实现 IComparable 更灵活的解决方案,因为只能有一个 IComparable 实现。

在您的示例中,SignalValue<T> 有一个 public Value,因此实际上不需要 CompareTo 方法。任何想要比较值的人都可以 mySignalValue.Value.CompareTo(myOtherSignalValue.Value),不需要实现 IComparable。