匹配数值类型的泛型约束

我正在尝试编写一个关于数值类型的扩展方法,以便在我正在构建的流畅的测试框架中使用。基本上,我想这样做:

public static ShouldBeGreaterThan<T>(this T actual, T expected, string message)
where T : int || T: double || etc...

只有 where T : struct不行,因为它也会匹配 stringbool,可能还有一些其他的东西我忘记了。有什么办法只匹配数字类型吗?(特别是实现 ><操作符的类型,所以我可以对它们进行比较... ... 如果这意味着我也在匹配日期,那么这并不重要——扩展仍然可以完成我预期的工作。)

55899 次浏览

Stackoverflow is littered with this kind of question. Take a look at this search. C# doesn't support a way to define a generic type constrained by numbers. Sadly, your best bet is to implement the extension method on all objects and do a switch based on type or to create a set of methods for ints, doubles, floats, etc.

In this case you want to constrain your generic to the IComparable interface, which gives you access to the CompareTo method, since this interface allows you to answer the question ShouldBeGreaterThan.

Numeric types will implement that interface and the fact that it also works on strings shouldn't bother you that much.

public static bool IsGreaterThan<T>(this T actual, T comp) where T : IComparable<T>
{
return actual.CompareTo(comp) > 0;
}

You can add the struct constraint if you want as well.

It is hard to limit to just numerics, since there is nothing common like INumeric to use as the filter. Actually, I suspect the easiest approach here is to not insist on the constraint, and use Comparer<T>.Default.Compare inside the method.

This inbuilt type supports both the generic IComparable<T> and the non-generic IComparable, and supports ref-types, value-types and lifted usage via Nullable<T>.

For full operator usage, look at MiscUtil's Operator class and GreaterThan etc, which may be useful if you really want to use the operator (rather than the interface). It also provides access to the other operators like Add etc.

where T : struct,
IComparable,
IComparable<T>,
IConvertible,
IEquatable<T>,
IFormattable

That's the closest I can get to a numeric constraint. All the numeric types implement these 5 interfaces, but IFormattable is not implemented by bool, and strings are a reference type, so they're not applicable.

There's some other things that implement these - DateTime for example, so it's not really as required, but prevents a lot of instantiations you don't want.

This workaround may help: Workaround using policies. It provides compile time safety.