一个二元运算符的参数之一必须是包含类型 c#。

13
public static int[,] operator *(int[,] arr1, int[,] arr2)
    {
        int sum;
        int[,] res = new int[arr1.GetLength(0), arr2.GetLength(1)];
        for (int i = 0; i < arr1.GetLength(0); i++)
        {
            for (int j = 0; j < arr2.GetLength(1); j++)
            {
                sum = 0;
                for (int k = 0; k < arr1.GetLength(1); k++)
                {
                    sum = sum + (arr1[i, k] * arr2[k, j]);
                }
                res[i, j] = sum;
                //Console.Write("{0} ", res[i, j]);
            }
            //Console.WriteLine();
        }

        return res;
    }

我正在尝试重载*运算符以将两个矩阵相乘,但编译器一直显示错误:

"一个二元运算符的参数必须是包含类型c#"

请告诉我代码中的问题以及如何解决它。


1
编译器告诉你问题所在——你不能像那样重载任意运算符……你只能重载其中一个操作数(或转换的返回类型)是你声明运算符的类型的运算符。 - Jon Skeet
我必须承认,最初我像 OP 一样感到困惑,因为我来自 C++(考虑自由函数)。但是后来发现,C# 不像 C++ 那么宽容。 - mireazma
1个回答

14

编译器已经在告诉你哪里出了问题 - 但引用C#5规范的7.3.2节:

用户定义的运算符声明始终需要至少一个参数为包含该运算符声明的类或结构体类型。因此,用户定义的运算符不能具有与预定义运算符相同的签名。

换句话说,以下写法是可以的:

class Foo
{
    public static int[,] operator *(int[,] arr1, Foo arr2)
    {
        ...
    }
}

...因为第二个运算对象是声明的类型。但在您的情况下,两个操作数都是 int[,]

您可以添加扩展方法:

public static class ArrayExtensions
{
    public static int[,] Times(this int[,] arr1, int[,] arr2)
    {
        ...
    }
}

那么你可以:

int[,] x = ...;
int[,] y = ...;
int[,] z = x.Times(y);

另一种解决方案 - 在我看来更好的一种,是声明您自己的Matrix类来封装矩阵运算。然后您可以定义自己的乘法运算符:

public static Matrix operator *(Matrix left, Matrix right)

...并且您不会干涉那些不打算被视为矩阵的int[,]数组。


1
我来这里就是为了得到这个答案,但公平地说,很容易把错误理解为它认为arr1或arr2都不是int[,](包含类型)。现在我明白它的意思了,但我要说编译器并没有清楚地说明实际问题所在。arr1和arr2都是包含类型:int[,]。 - Jesse Williams
@JesseWilliams:我个人认为,“包含类型”指的是“包含运算符的类型”,而不是int[,]。在这种情况下,int[,]怎么能成为“包含”类型呢? - Jon Skeet
1
一旦你理解了它,它就很有意义 - 只是很容易误解。显然,“Containing”指的是声明当前所在的类。但是,至少从这些错误通常的写法来看,很容易将其与返回类型而非父类相关联。是的,如果他们指的是返回类型,他们会说返回类型 - 我同意。但对于你通常不做的事情,很容易误解。/耸肩 不过,解决起来很简单。 - Jesse Williams

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接