假设我想要一个带有任何数字的方法,是否有可以使用的基类(或其他一些概念)?
据我所知,我必须为所有不同的数字类型(Int32,Int16,Byte,UInt32,Double,Float,Decimal等)进行重载.这看起来非常乏味.或者使用类型"对象"并抛出异常,如果它们不可转换或可分配给double - 这是非常糟糕的,因为它意味着没有编译时间检查.
更新: 好的感谢您的评论,你是对的Scarecrow和Marc,实际上宣称它为Double实际上除了Decimal以外的所有人都适用.
所以我正在寻找的答案是Double - 它在这里就像一个基类,因为大多数数字类型都可以分配给它.(我猜Decimal不能分配给Double,因为它可能会变得太大.)
public void TestFormatDollars() {
int i = 5;
string str = FormatDollars(i); // this is OK
byte b = 5;
str = FormatDollars(b); // this is OK
decimal d = 5;
str = FormatDollars(d); // this does not compile - decimal is not assignable to double
}
public static string FormatDollars(double num) {
return "$" + num;
}
Run Code Online (Sandbox Code Playgroud)
mik*_*son 24
答案是:您不需要为所有数字类型提供重载,仅适用于Double和Decimal.所有其他的(除了一些非常大的异常)将自动转换为这些.
不是基类,但事实上那是红鲱鱼.基类System.ValueType没有多大帮助,因为它包含非数字类型.我正在阅读的语言参考是让我困惑的第一个地方:)
(我只是在找谁归因于答案,它是Scarecrow和Marc Gravell的组合,但因为他们是评论我已经把答案放在这里)
Mar*_*ell 13
没有一个(或者至少没有一个只是意味着"数字").你可以使用:
void Foo<T>(T value) where T : struct {...}
Run Code Online (Sandbox Code Playgroud)
但这允许任何结构 - 而不仅仅是数字.如果要进行算术运算,可以使用泛型运算符.除此之外; 超载它是最可行的选择.
我所做的:
public interface INumeric<T>
{
T Zero { get; }
T One { get; }
T MaxValue { get; }
T MinValue { get; }
T Add(T a, T b);
// T Substract(....
// T Mult...
}
public struct Numeric:
INumeric<int>,
INumeric<float>,
INumeric<byte>,
INumeric<decimal>,
// INumeric<other types>
{
int INumeric<int>.Zero => 0;
int INumeric<int>.One => 1;
int INumeric<int>.MinValue => int.MinValue;
int INumeric<int>.MaxValue => int.MaxValue;
int INumeric<int>.Add(int x, int y) => x + y;
// other implementations...
}
Run Code Online (Sandbox Code Playgroud)
现在,您可以在方法中使用它:
bool IsZero<TNum, T>(TNum ops, T number)
where TNum : INumeric<T>
{
return number == ops.Zero;
}
Run Code Online (Sandbox Code Playgroud)
或扩展方法
public static bool IsZero<TNum, T>(this TNum ops, T number)
where TNum : INumeric<T>
{
return number == ops.Zero;
}
Run Code Online (Sandbox Code Playgroud)
在你的代码中:
...
var n = new Numeric(); // can be an static prop
Console.WriteLine(IsZero(n, 5)); // false
Console.WriteLine(IsZero(n, 0f)); // true
Console.WriteLine(IsZero(n, "0")); // compiler error
Run Code Online (Sandbox Code Playgroud)
或者,使用扩展方法:
Console.WriteLine(n.IsZero(5)); // false
Console.WriteLine(n.IsZero(0f)); // true
Console.WriteLine(n.IsZero("0")); // compiler error
Run Code Online (Sandbox Code Playgroud)
在 .NET 7 中,终于引入了用于通用数学的新 API 。
.NET 7 向基类库引入了新的与数学相关的通用接口。这些接口的可用性意味着您可以将泛型类型或方法的类型参数限制为“类似数字”。
它具有INumber<T>
现在由所有数字类型实现的接口,因此您可以执行以下操作:
public static string FormatDollars<T>(T num) where T : INumber<T>
{
return "$" + num;
}
Run Code Online (Sandbox Code Playgroud)
它还提供细粒度的数字接口来识别类型类别,例如:
IBinaryInteger<T>
为了Byte
(byte
),Int16
(short
),Int32
(int
),Int64
(long
), ...IFloatingPoint<T>
为了Double
(double
),decimal
(Decimal
), ...对于运算符,它提供了由所有数字类型实现的各种运算符接口。
IAdditionOperators<TSelf,TOther,TResult>
为加( +
)。IMultiplyOperators<TSelf,TOther,TResult>
为乘法 ( *
)。我假设您的问题不是明确关于值类型而是关于数字类型。但是,如果您还需要强制执行值类型的泛型类型约束,请指定两者。
public static string FormatDollars<T>(T num) where T : struct, INumber<T>
{
return "$" + num;
}
Run Code Online (Sandbox Code Playgroud)