Reputation: 22136
Say I want to have a method that takes any kind of number, is there a base class (or some other concept) that I can use?
As far as I know I have to make overloads for all the different numeric types (Int32
, Int16
, Byte
, UInt32
, Double
, Float
, Decimal
, etc). This seems awfully tedious. Either that or use the type object
and throw exceptions if they are not convertible or assignable to a double
- which is pretty bad as it means no compile time checking.
UPDATE:
OK thanks for the comments, you are right Scarecrow and Marc, in fact declaring it as Double
actually works for all except Decimal
.
So the answer I was looking for is Double
- it acts like a base class here since most numeric types are assignable to it. (I guess Decimal
is not assignable to Double
, as it could get too big.)
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;
}
Upvotes: 63
Views: 47692
Reputation: 1062715
There isn't one (or at least, not one that just means "numbers"). You could use:
void Foo<T>(T value) where T : struct {...}
But that allows any struct - not just numbers. If you want to do arithmetic, generic operators may be of use. Other than that; overloads it the most viable option.
Upvotes: 15
Reputation: 22089
In .NET 7 a new API for generic math was finally introduced.
.NET 7 introduces new math-related generic interfaces to the base class library. The availability of these interfaces means you can constrain a type parameter of a generic type or method to be "number-like".
It features the INumber<T>
interface that is now implemented by all numeric types, so you can do this:
public static string FormatDollars<T>(T num) where T : INumber<T>
{
return "$" + num;
}
It also provides fine-grained numeric interfaces to identify type categories, e.g.:
IBinaryInteger<T>
for Byte
(byte
), Int16
(short
), Int32
(int
), Int64
(long
), ...IFloatingPoint<T>
for Double
(double
), decimal
(Decimal
), ...For operators it offers a variety of operator interfaces that are implemented by all numeric types.
IAdditionOperators<TSelf,TOther,TResult>
for plus (+
).IMultiplyOperators<TSelf,TOther,TResult>
for multiply (*
).I assume that your question was not explicitly about value types but numeric types. However, if you need generic type constraints that enforce value types as well, specify both.
public static string FormatDollars<T>(T num) where T : struct, INumber<T>
{
return "$" + num;
}
Upvotes: 10
Reputation: 437
What I do:
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...
}
Now, you can use it in a method:
bool IsZero<TNum, T>(TNum ops, T number)
where TNum : INumeric<T>
{
return number == ops.Zero;
}
or extension method
public static bool IsZero<TNum, T>(this TNum ops, T number)
where TNum : INumeric<T>
{
return number == ops.Zero;
}
and in your code:
...
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
or, with extension method:
Console.WriteLine(n.IsZero(5)); // false
Console.WriteLine(n.IsZero(0f)); // true
Console.WriteLine(n.IsZero("0")); // compiler error
Upvotes: 12
Reputation: 22136
The answer is: you don't need to provide overloads for ALL the numeric types, just for Double and Decimal. All others (except maybe some very unusually large ones) will be automatically converted to these.
Not a base class but in fact that was the red herring. The base class System.ValueType doesn't help much as it includes types that are not numerics. The language reference i was reading was what got me confused in the first place :)
(I was just looking for who to attribute the answer to and it was a combination of Scarecrow and Marc Gravell, but since they were comments i have put the answer here)
Upvotes: 31
Reputation: 4977
The short answer is: Numeric types are value types, hence they derive from System.ValueType. The full answer is: you should read this article from MSDN. Moreover I think that you should read C# language reference :). Value type not equals numeric type, because values types include also structures and enumerations.
Upvotes: 9
Reputation: 14888
Are overloaded method signitures out of the question here? If you want a constrained group of methods to performe the same task you could voerload the public method and call a private method that takes any number via casting the input to a double.
Upvotes: 0