如何使二进制乘法运算符 * 在泛型类中可用

本文关键字:泛型类 运算符 何使 二进制 | 更新日期: 2023-09-27 18:21:42

abstract class Shape<T>
{
    public abstract T Area();
}
class Square<T> : Shape<T>
{
    T side;
    public Square(T side)
    {
        this.side = side;
    }
    public override T Area()
    {
        return this.side * this.side;
    }
}

错误 1 运算符"*"不能应用于类型"T"和类型"T"的操作数。

编译器抛出错误,因为没有this.side*this.side*。如何使二进制乘法运算符*在泛型类中可用?

如何使二进制乘法运算符 * 在泛型类中可用

不能使用 * 运算符本身,但可以通过生成使用此运算符的表达式来解决它:

static class Operators
{
    public static T Multiply<T>(T x, T y)
    {
        return OperatorCache<T>.Multiply(x, y);
    }
    static class OperatorCache<T>
    {
        static OperatorCache()
        {
            Multiply = MakeBinaryOperator(ExpressionType.Multiply);
        }
        static Func<T, T, T> MakeBinaryOperator(ExpressionType type)
        {
            var x = Expression.Parameter(typeof(T), "x");
            var y = Expression.Parameter(typeof(T), "y");
            var body = Expression.MakeBinary(type, x, y);
            var expr = Expression.Lambda<Func<T, T, T>>(body, x, y);
            return expr.Compile();
        }
        public readonly static Func<T, T, T> Multiply;

    }
}

然后,您可以像这样使用它:

public override T Area()
{
    return Operators.Multiply(this.side, this.side);
}

当然,您可以将其他运算符添加到Operators类中;请记住,如果您使用的运算符未为 T 定义,它将在运行时失败

你不能

那样做。并非所有类型都定义了乘法运算符。但是泛型没有约束,因此编译器必须假定类的使用者可以使用任何类型,例如string

遗憾的是,.NET 中的泛型约束不能用于表达这种要求,即无法将T限制为仅定义乘法运算符的类型。

底线是:不能在方案中使用泛型。您需要采用与.NET框架相同的方式,包括其Size(对于double(和SizeF(对于float(类型。

注意我的答案的上下文:
如果你想为你控制的任意类提供你的类,阿列克谢有正确的答案。
但是,如果您想将Square类与doublefloatint等类型一起使用,他的答案则不适用,因为您无法向它们添加接口。

你可以用方法替换它.Multiply(T a, T b)并与界面一起使用

public interface IMultiplyable<T>
{
     T Multiply(T a, T b);
}