Looks like it's part of a much larger discussion that's going to take a while to make it into the language (if it ever does): Champion "Type Classes (aka Concepts, Structural Generic Constraints)" · Issue #110 · dotnet/csharplang · GitHub[^] Meanwhile, you can "fake" it by using Jon Skeet's generic operators from the MiscUtil project: Generic Operators[^] It hasn't been updated since 2009, but the concept still works. For example:
using System.Linq.Expressions;
public static class GenericOperators<T>
{
public static readonly Func<T, T, T> Add = Create(Expression.Add);
public static readonly Func<T, T, T> Subtract = Create(Expression.Subtract);
public static readonly Func<T, T, T> Multiply = Create(Expression.Multiply);
public static readonly Func<T, T, T> Divide = Create(Expression.Divide);
private static Func<T, T, T> Create(Func<Expression, Expression, BinaryExpression> body)
{
try
{
Type typeT = typeof(T);
var left = Expression.Parameter(typeT, "left");
var right = Expression.Parameter(typeT, "right");
if (typeT.IsEnum)
{
Type enumType = Enum.GetUnderlyingType(typeT);
var x = Expression.Convert(left, enumType);
var y = Expression.Convert(right, enumType);
Expression op = body(x, y);
if (op.Type == enumType) op = Expression.Convert(op, typeT);
return Expression.Lambda<Func<T, T, T>>(op, left, right).Compile();
}
return Expression.Lambda<Func<T, T, T>>(body(left, right), left, right).Compile();
}
catch (InvalidOperationException ex)
{
string message = ex.Message;
return delegate { throw new InvalidOperationException(message); };
}
catch (ArgumentException ex)
{
string message = ex.Message;
return delegate { throw new InvalidOperationException(message); };
}
}
}
Of course, it wouldn't help much in this case, because you'd still n