如果我想获取某个目录中所有文件的列表,我可以输入类似的内容:
var files = (new DirectoryInfo(@"C:\Temp")).GetFiles();
但是,以下内容也有效(请注意“new”关键字之前缺少括号):
var files = new DirectoryInfo(@"C:\Temp").GetFiles();
为什么允许这种情况发生?声明如下:
2 + 4 * 3 and (2 + 4) * 3
由于括号,将分别解析为14和18。
似乎我的代码示例类似于在DirectoryInfo对象的静态版本上调用“.GetFiles()”方法(因为缺少“new”关键字),其中括号与“新的“关键字使我明确表示我正在使用DirectoryInfo对象的实例。
即:
2 + 4 * 3
new DirectoryInfo() .GetFiles()
VS
(2 + 4 ) * 3
(new DirectoryInfo()) .GetFiles()
为什么会出现这种情况,有一个简单的解释吗? C#词法分析器处理这两种情况(有/无括号)不是更有效吗?我的比喻有缺陷吗?
答案 0 :(得分:8)
注意:这个答案有很多表达方式,彼此相同。我没有将它们内联或分成两行,而是采用
<==>
的简写来表示&#34;相当于&#34;。所以foo <==> bar
应该被理解为&#34;表达式
foo
等同于表达式bar
&#34;。
您正在谈论的是优先级。 *
的优先级高于二进制+
运算符,因此它&#34;绑定其操作数&#34;更严格。所以:
x * y + z <==> (x * y) + z
new
和&#34;点&#34;部分是主要表达式,它们具有相同的优先级。
当两个表单具有相同的优先级时,将涉及 associativity 。当涉及new
运算符时,C#规范实际上并不十分清楚,但.
运算符是二元运算符,并且所有二元运算符都被认为是 left-缔合。换句话说:
x.y.z <==> (x.y).z
另一个例子是,*
和/
具有相同的优先级,因此:
x * y / z <==> (x * y) / z
x / y * z <==> (x / y) * z
因此:
new DirectoryInfo(x).GetFiles() <==> (new DirectoryInfo()).GetFiles()
所有这些都与评估顺序有些分开,评估顺序始终从左到右。例如,在表达式x + y * z
中,*
的优先级越高意味着:
x + y * z <==> x + (y * z)
...但它仍然x
首先进行评估,然后是y
,然后是z
,然后是乘法,最后是加法。正常情况下,Eric Lippert writes extremely well on this topic。
答案 1 :(得分:4)
请参阅有关优先级的MSDN上的文章:7.2.1
由于所有非赋值二元运算符都是左关联的,因此从左到右对前同步new
和.
运算符进行求值。
因此,在给定的表达式中,在调用其方法之前对象进行实例化。此外 - new
具有等同优先权,因此它会在.
获得之前使用类型标识符(从左到右)。
答案 2 :(得分:3)
调用静态方法的语法是DirectoryInfo.GetFiles()
而不是DirectoryInfo(...).GetFiles()
,因此我不确定这两种解释之间是否存在冲突。
无论哪种方式,具有数值表达式的示例将首先乘以3,因为乘法具有比加法或减法更高的优先级。所有括号都允许您覆盖默认优先级。
即使语法与调用静态方法相同,在您询问的情况下,默认优先级仍然会导致它在没有括号的情况下按预期工作。
答案 3 :(得分:2)
您不能new
返回值,因此编译器知道将new添加到初始化类型,并在新实例上运行该方法。
(new A()).Foo() // Makes sense! sort of...
new (A().Foo()) // Makes absolute no sense.
(1 + 4) * 10 // Makes sense
1 + (4 * 10) // Also makes sense
数字与C#关键字之间的协同工作逻辑有所不同。
答案 4 :(得分:1)
你的比喻适用于数学运算的顺序。但是在语法上使用new表示编译器已经为类的“新”实例做好了准备。无论是否括号,您可以使用关键字new来获得该类的新实例。