取消引用*与乘法*歧义

时间:2017-08-21 09:57:41

标签: c#

在Main()的最后一行,我尝试做指针内容时出错,但我实际上要做的是调用我在Foo类中定义的乘法运算符。如果那不是调用乘法的语法,那么是什么?

namespace test
{
    class Program
    {
        class Foo
        {
            int foo;
            public Foo(int n)
            {
                foo = n;
            }
            public static object operator *(Foo a,Foo b)
            {
                return new Foo(a.foo * b.foo);
            }
        }
        static void Main(string[] args)
        {
            Foo a = new Foo(2);
            Foo b = new Foo(3);
            a * b;
        }
    }
}

我确定这是愚蠢的,但我没有看到它。

1 个答案:

答案 0 :(得分:3)

在C#中,唯一可以用作语句的表达式(即您可以评估并简单地忽略评估结果的表达式)是:

  • 作业a = b;
    • 最明显的有效语句,但即使是赋值表达式也有结果值,这意味着你可以编写像if ((a = b) == c) doStuff();这样的单行 - 所以你仍然没有使用"执行明文赋值时赋值表达式的结果
  • 方法调用doStuff();
    • 即使doStuff返回值,也可以将其用作语句
    • 如果您在未将a.ToString();存储在任何地方的情况下致电string,则编译器不会抱怨
  • 递增/递减i++;i--;
    • post / pre-increment结果语义在所有类C语言中几乎相同,如果你使用结果(如在var x = i++;中)或不在
    • 那么无关紧要
  • 等待方法await doAsyncStuff();
    • 您可以等待异步操作而不必使用结果(这基本上类似于普通方法调用)
  • new对象表达式new Foo();
    • 即使你没有将新实例化的对象分配给任何东西,它的构造函数也可能做很多影响程序状态的事情,并且创建对它自己的静态引用(否则它只会被收集)

因此,由于不使用此操作的结果(将其分配给变量),C#编译器假定您尝试定义b类型的变量a*

static void Main(string[] args)
{
    Foo a = new Foo(2);
    Foo b = new Foo(3);

    // this is seen by the compiler as "type* variable;"
    a * b;
}

这就是为什么它会给你带来几个编译错误,比如:

  • a是一个变量,但正在用作
  • 类型
  • 指针只允许在不安全的上下文中使用

如果您使用+运算符,它就不会提到任何指针,它会抱怨您不应该将该表达式用作语句,因此可能会让它更明显。

要解决错误,请将表达式的结果分配给变量:

// type of `result` is an object, btw
var result = a * b;

作为旁注,明智的做法是operator *方法返回Foo类型的结果,而不是普通的object

public static Foo operator *(Foo a, Foo b) 
{
    ...
}

// type of `result` is now `Foo`, as it should be
Foo result = a * b;

最后的建议是,这个具体的例子是不可变的struct的合适候选者,而不是classsimilar to the Point struct, for example)。