有没有一种方法可以重构这个 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。
我目前有一个泛型接口和一个泛型类型,分别是 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。