What you can do is create a common interface that includes the operations you want to support, create a common factory to create instances of supported types to perform operations and use them.
eg.
public interface IOperations<T> { T Add(T a, T b); T Subtract(T a, T b); T Multiply(T a, T b); T Divide(T a, T b); } public static class Operations<T> { public static IOperations<T> Default { get { return Create(); } } static IOperations<T> Create() { var type = typeof(T); switch (Type.GetTypeCode(type)) { case TypeCode.Byte: return (IOperations<T>)new ByteOperations(); case TypeCode.Single: return (IOperations<T>)new SingleOperations(); default: var message = String.Format("Operations for type {0} is not supported.", type.Name); throw new NotSupportedException(message); } } class ByteOperations : IOperations<byte> { public byte Add(byte a, byte b) { return unchecked ((byte)(a + b)); } public byte Subtract(byte a, byte b) { return unchecked ((byte)(a - b)); } public byte Multiply(byte a, byte b) { return unchecked ((byte)(a * b)); } public byte Divide(byte a, byte b) { return unchecked ((byte)(a / b)); } } class SingleOperations : IOperations<float> { public float Add(float a, float b) { return a + b; } public float Subtract(float a, float b) { return a - b; } public float Multiply(float a, float b) { return a * b; } public float Divide(float a, float b) { return a / b; } } }
T Mean<T>(IList<T> numbers) { var operations = Operations<T>.Default; var sum = numbers.Aggregate(operations.Add); var count = (T)Convert.ChangeType(numbers.Count, typeof(T)); return operations.Divide(sum, count); } var resultByte = Mean(new byte[] { 1, 2, 3, 4 });
If you are not opposed to a small performance hit, you can dynamically create the necessary operations.
class GenericOperations<T> : IOperations<T> { public GenericOperations() { add = CreateLambda(Expression.Add); subtract = CreateLambda(Expression.Subtract); multiply = CreateLambda(Expression.Multiply); divide = CreateLambda(Expression.Divide); } private Func<T, T, T> add, subtract, multiply, divide; private static Func<T, T, T> CreateLambda(Func<Expression, Expression, BinaryExpression> op) { var a = Expression.Parameter(typeof(T), "a"); var b = Expression.Parameter(typeof(T), "b"); var body = op(a, b); var expr = Expression.Lambda<Func<T, T, T>>(body, a, b); return expr.Compile(); } public T Add(T a, T b) { return add(a, b); } public T Subtract(T a, T b) { return subtract(a, b); } public T Multiply(T a, T b) { return multiply(a, b); } public T Divide(T a, T b) { return divide(a, b); } }