This is how I would like to be able to write my code. MethodB is just a dummy here, all we care about is that it's returning type T.
public static class ClassA<T> where T: struct, INumber<T>
{
public static T MethodA( T[][] matrix, T[] vector)
{
T result = T.Zero;
int m = matrix.Length;
for(int i = 0; i < m; i++)
{
result += MethodB( matrix[i], vector);
}
return result / ( m * 2 + 1);
}
public static T MethodB(T[] vector1, T[] vector2)
{
T result = T.One;
return result;
}
}
The problem is the return statement of MethodA. I run into CS0019. To fix this I would like to convert m into type T. I know that all T, which will ever be used, are going to be numbers which should allow for a constructor using m as a single argument. So I would like to have a way to convert m.
A workaround to my problem I found is:
public static class ClassA<T> where T: struct, INumber<T>
{
public static T MethodA( T[][] matrix, T[] vector)
{
T result = T.Zero;
int m = matrix.Length;
for(int i = 0; i < m; i++)
{
result += MethodB( matrix[i], vector);
}
T convertedM = CreateT( m * 2 + 1);
return result / convertedM;
}
public static T MethodB( T[] vector1, T[] vector2)
{
T result = T.One;
return result;
}
public static T CreateT( int i)
{
T type = new T();
if (type is double)
{
double d =(double) i;
return (T)((object)d);
}
if (type is float)
{
float d =(float) i;
return (T)((object)d);
}
//here would be a long list of different number types.
throw new NotImplementedException();
}
}
This seems like a suboptimal solution to me though, since I have to check against all possible types. It feels like I am missing the obvious solution, like having an interface that makes sure int conversion is implemented for all T, but I don't know how to do that. I would like to be able to add different number systems and use the oney given by the language.
What I tried:
You can use one of the CreateChecked
, CreateTruncating
or CreateSaturating
methods on the INumber<T>
type.
For example:
return result / T.CreateChecked(m * 2 + 1);
CreateChecked: Creates an instance of the current type from a value, throwing an overflow exception for any values that fall outside the representable range of the current type.
CreateTruncating: Creates an instance of the current type from a value, truncating any values that fall outside the representable range of the current type.
CreateSaturating: Creates an instance of the current type from a value, saturating any values that fall outside the representable range of the current type.