C#中为何NameOf(foo.First.Bar)可用但NameOf(foo[0].Bar)报错?
技术原理说明
这个差异是C#语言规范对nameof表达式的编译期语法约束直接决定的,和运行时行为无关:
nameof是纯编译期常量表达式,编译器不会执行参数里的任何代码逻辑,只会静态提取访问链最末端的标识符名称作为返回值,但参数本身必须符合规范限定的合法表达式形态。- 合法的
nameof参数仅允许三类语法形态:- 单个标识符的简单名称,比如
nameof(foo) - 由
.连接的连续成员访问链,不管中间节点是命名空间、类型、属性、字段、方法组,只要是纯成员访问语法就合法 - 符合规则的base访问、限定类型名访问表达式
- 单个标识符的简单名称,比如
两种场景的行为差异完全来自语法形态的区别:
NameOf(foo.First.Bar)属于纯成员访问链:全程只用.做成员连接,哪怕First是方法名,只要没有加调用括号(),就只是对方法组成员的静态引用,不存在任何调用或计算逻辑,编译器可以直接提取最末端的Bar作为返回值,因此可以正常编译。NameOf(foo[0].Bar)包含索引器访问子表达式foo[0]:方括号[]带参数的索引器访问本质是调用类型的索引器get方法,属于规范明确禁止的「调用类子表达式」——同类被禁止的还有带括号的方法调用(比如foo.First().Bar)、运算符计算表达式等。这类表达式代表需要在运行时执行计算才能得到结果的逻辑,不存在可以静态绑定的固定标识符,允许这类写法既不符合nameof获取静态标识符名的设计目标,也会增加无意义的编译器复杂度,因此会直接抛出你看到的编译错误。
补充说明:
nameof做语法校验时不会检查成员访问链是否真的能在运行时执行,比如nameof(string.Length)完全可以正常编译返回"Length",哪怕string是密封类,不存在可供访问实例Length的对象,只要语法形态符合纯成员访问的要求就会放行。
内容的提问来源于stack exchange,提问作者jmiguel
相关产品推荐
相关产品推荐

