9

如果你有:

F(G<A,B>(4));

这是否意味着用户想要调用具有 2 个参数的方法 F,这些参数是比较 G 和 A,以及 B 和常数 4 的结果?

或者它是否意味着调用 F 并使用类型参数 A 和 B 以及参数 4 调用泛型方法 G 的结果?

4

2 回答 2

7

所以我试了一下只是为了确定。事实证明这很好用:

void F(int x) { }
int G<T, U>(int x) { return x; }

class A { }
class B { }

void Main()
{
    F(G<A,B>(4));
}

但这会产生一些编译错误:

void F(bool x, bool y) { }

void Main()
{
    int G = 0, A = 1, B = 2;
    F(G<A,B>(4));
}

找不到类型或命名空间名称“A”(按 F4 添加 using 指令或程序集引用)

找不到类型或命名空间名称“B”(您是否缺少 using 指令或程序集引用?)

变量“G”不是通用方法。如果您想要一个表达式列表,请在 < 表达式周围使用括号。

所以答案是表达式F(G<A,B>(4))被解释为泛型函数调用。有许多方法可以强制编译器将其视为两个参数的单个函数调用:F(G<A,B>4)F((G)<A,B>(4))F(G>A,B>(4)),仅举几例。

于 2013-08-06T04:33:07.573 回答
6

您应该阅读 C# 规范的 7.6.4.2,它处理语法歧义并几乎逐字讨论此示例。去引用:

如果可以(在上下文中)将标记序列解析为以类型结尾的简单名称(第 7.6.2 节)、成员访问(第 7.6.4 节)或指针成员访问(第 18.5.2 节) -argument-list(第 4.4.1 节),>检查紧跟在结束标记之后的标记。如果它是其中之一

( ) ] } : ; , . ? == != | ^

然后类型参数列表被保留为简单名称、成员访问或指针成员访问的一部分,并且丢弃标记序列的任何其他可能的解析。

这里,G是一个简单名称,问题是是否<A,B>要被解释为类型参数列表作为这个简单名称的一部分。

(后面有一个>,所以片段G<A,B>是方法的简单名称。该方法是具有类型参数的泛型方法,A并且B参数为 4。F因此是具有单个参数的方法。

需要注意的一件有趣的事情是,如果解析失败,编译器不会考虑任何替代方案。正如您从 pswg 的回答中看到的那样,即使唯一有效的解释是一种F采用两个参数的方法,也不会考虑它。

于 2013-08-06T04:39:47.207 回答