I want to write generic class which is intended to work with built-in types like byte
and ushort
. In internal computations I need to cast generic type to integer and back to generic type. I found the way to compile such code, for example:
class Test<T> where T : struct, IConvertible
{
public static T TestFunction(T x)
{
int n = Convert.ToInt32(x);
T result = (T)Convert.ChangeType(n, typeof(T));
return result;
}
}
I think that using such conversions may significantly reduce performance, if they are used in computation loops. Is there a better way to make these conversions?
int
to T
conversion is a bit tricky. I think you could use Expression
class here.
Test<T>
class should can look like that:
class Test<T> where T : struct, IConvertible
{
private static Func<int, T> _getInt;
static Test()
{
var param = Expression.Parameter(typeof(int), "x");
UnaryExpression body = Expression.Convert(param, typeof(T));
_getInt = Expression.Lambda<Func<int, T>>(body, param).Compile();
}
public static T TestFunction(T x)
{
int n = Convert.ToInt32(x);
T result = _getInt(n);
return result;
}
}
It prepares _getInt = x => (T)x
for you in static constructor and uses it later, to convert int
to T
.
After some thinking, I'm happy that thanks to the question and some answers I have resolved an old problem of mine: using operations on generic T:
First the example with Cast (as requested by the OP)
public static class Cast<T, U>
{
public static readonly Func<T, U> Do;
static Cast()
{
var par1 = Expression.Parameter(typeof(T));
Do = Expression.Lambda<Func<T, U>>(Expression.Convert(par1, typeof(U)), par1).Compile();
}
}
And then an example with multiplication:
public static class Multiply<T>
{
public static readonly Func<T, T, T> Do;
static Multiply()
{
var par1 = Expression.Parameter(typeof(T));
var par2 = Expression.Parameter(typeof(T));
Do = Expression.Lambda<Func<T, T, T>>(Expression.Multiply(par1, par2), par1, par2).Compile();
}
}
The use is quite simple:
int x = Conv<T, int>.Do(someTValue);
in the end a static class is created, with a single field that is a readonly static property named Do
that is a delegate that "points" to an operation built with an Expression tree.
The multiplication is similar:
T res = Multiply<T, T>.Do(someTValue1, someTValue2);
The multiplication is somewhat 3x slower in the general case than a direct multiplication (in Release mode, no debugging).
Clearly doing the other operations is simple by starting from Multiplication
(it's interesting that I knew quite well of Expression
trees, but I hadn't ever thought of using static classes as "dictionaries" for containing the various types. I always did something like Dictionary<Type, Delegate>
instead of letting the .NET "handle" the Dictionary
through generic class specialization.)