4

这个问题的启发,我在 Mono 2.10.9 和 Visual Studio 2010 上尝试了以下代码:

public class Example
{
    public static void Main()
    {
        Foo(1);
    }

    public static void Foo( dynamic x )
    {
        Example.Bar(x);
    }

    static void Bar( dynamic x )
    {
        x++;
    }

    int count;
    void Bar( int x )
    {
        count++;
    }
}

正如你所看到的,Foo是静态的,所以它只能访问静态Bar——我明确地调用了静态版本!

我知道我无法声明static void Bar( int x ),因为存在非静态版本。

但是,将非静态的参数类型更改Bar为,比如说,字符串,一切都会好起来的。

这是为什么?这里有什么规则?是否可以调用静态方法?

也许这是一个 Mono DLR 问题?

编辑:为了澄清。我想知道什么规则将对静态方法的显式调用(至少我认为它是显式的)转换为对非静态方法的调用?从静态上下文来看,这显然是不可能的。

或者,如果没有这样的规则,它会是一个错误吗?可以以某种方式避免这种行为吗?

4

2 回答 2

1

那里的关键声明是“我知道我将无法声明 static void Bar(int x),因为存在非静态版本。”。使用 dynamic 关键字将重载决议推迟到运行时,但是当运行时出现时,它并不能免除您的规则。

当重载解决方案最终发生时,DLR 会评估所有可用选项,然后选择最佳选项。在此解决时间之前,动态类型的参数的行为与对象类型非常相似(请参见此处)。因此,通常采用 int 的更具体的方法将是过载解决方案的赢家,因此被选择而不是采用动态/对象的方法。这意味着实例方法通常会获胜。DLR 知道具有相同签名的两个方法不能因静态而异。在评估可用选项时,您期望它会说“啊哈!在这种情况下,静态 void Bar(dynamic x) 可以解释为静态 void Bar(int x)”。但是,如果它确实这么说,那么关于没有其他相同的静态和非静态方法的规则将被违反。它的内部选项列表将包含静态和非静态 Bar 方法,这两种方法都具有相同的签名。所以不能这么说。这留下了唯一的另一个选项,它恰好是一个实例方法。这在这种情况下没有用,因此 DLR 会引发 RuntimeBinderException。如果将实例 Bar 的参数更改为非 int 的参数,则方法签名不会发生冲突,因此 DLR 可以将静态动态 Bar 解释为采用 int 并选择该重载。

于 2013-01-13T01:25:36.877 回答
0
    static void Bar( dynamic x )
    {
        x++;
    }

    int count;
    void Bar( int x )
    {
        count++;
    }

静态函数可以被视为(因此任何使用 int 类型参数调用静态方法都会调用非静态、更适合的方法):

    static void Bar( dynamic x )
    {
        if (x is Int)
           Bar(x); //Count++

        else
           x++;
    }
于 2012-10-11T15:49:41.917 回答