为什么(AnObject).AField=AValue在VB.NET中是一个语法错误?

为什么(AnObject).AField=AValue在VB.NET中是一个语法错误?,vb.net,syntax,Vb.net,Syntax,编辑:修改代码示例以显式声明函数的返回类型 考虑以下最小示例: Class AClass Public AField As Integer Public Sub New(aField As Integer) Me.AField = aField End Sub Public Function AMethod() As Integer Return AField End Function End Class Modul

编辑:修改代码示例以显式声明函数的返回类型


考虑以下最小示例:

Class AClass
    Public AField As Integer

    Public Sub New(aField As Integer)
        Me.AField = aField
    End Sub

    Public Function AMethod() As Integer
        Return AField
    End Function
End Class

Module AModule

    Sub Main()

        Dim AnObject As AClass = New AClass(12)

        Dim n As Integer = (AnObject).AField  ' This is fine

        Dim m As Integer = (AnObject).AMethod() ' This is fine

        (AnObject).AField = 8 ' BC30035 Syntax Error

        AnObject.AField = 8 ' This is fine

    End Sub

End Module
VB.NET的语法是如何工作的,这两种情况之间存在差异?如果我们调用一个方法,或者读取一个字段,括号是允许的,但是如果我们写一个字段,括号是不允许的

我试着看了一下语法,但没有看到像正式语法这样的东西。我也尝试过用谷歌搜索这个,尽管要找到一组好的搜索关键词有点困难


更新

所以我看了Jimi链接的语言语法,我更困惑了——特别是我们有

RegularAssignmentStatement  ::=  Expression  Equals  Expression  StatementTerminator

Expression  ::= SimpleExpression  |  MemberAccessExpression  | ...

MemberAccessExpression  ::=
    [ MemberAccessBase  ] Period  IdentifierOrKeyword
        [  OpenParenthesis  Of  TypeArgumentList  CloseParenthesis  ]

MemberAccessBase  ::= Expression  | ...

SimpleExpression  ::= LiteralExpression | 
         ParenthesizedExpression  | 
         SimpleNameExpression |
         ... 

SimpleNameExpression  ::=  Identifier  [  OpenParenthesis  Of  TypeArgumentList  CloseParenthesis  ]

ParenthesizedExpression  ::=  OpenParenthesis  Expression  CloseParenthesis 
根据这种语法,这不是语法错误!具体来说,

  • AnObject
    是标识符,因此是SimpleNameExpression,因此是简单表达式,因此是表达式。(我没有在这里包括标识符的定义,但根据文档,字母字符字符串肯定是合格的。)
  • 因此,
    (一个对象)
    是一个圆括号表达式,因此是一个SimpleExpression,因此是一个表达式,因此是一个MemberAccessBase
  • AField
    是一个标识符
  • 将这两者放在一起,
    (一个对象)。AField
    是一个MemberAccessExpression,因此是一个表达式
  • 8
    是一个文字表达式,因此是一个表达式
  • 行末尾的换行符是语句终止符
  • 因此,根据此语法,
    (AnObject).AField=8
    是一个常规的赋值语句

因此,根据文档,这个语句应该被解析

我在这里纯粹是猜测,但我想说这是VB功能的一部分:

在您的代码中,编译器可能将
(AnObject)
视为一个值,而不是对原始对象的引用,确定对字段的赋值因此将被放弃,并且不允许该赋值


当然,即使通过值将
AnObject
传递给方法,修改
AnObject.Field
仍然会修改原始对象。因此,以此类推,代码应该是有效的。我猜VB编译器在这里应用了一个错误的启发式方法。

打开Option Strict,它会更清楚。@Jimi:介意详细说明吗?我同时启用了
选项Strict
选项Explicit
,唯一的变化是它抱怨我没有声明
AClass.AMethod的返回类型。一旦我将必需的
添加为整数
,我仍然有相同的语法错误,没有任何进一步的信息。@Jimi:或者你只是说我的代码示例会更清晰,让其他人可以阅读?。(.docx下载)-第2.2章除了@Jimi指导您的内容外,还可以查看“11.4.2括号表达式”一节,特别是“括号表达式的计算结果为括号内表达式的值”。我们讨论了适用于该语言作业的词汇语法。语言参考第10.6章中定义了常规作业。使用第2.2章中规定的一般规则评估赋值左半部分的语法。因此,
Dim i作为整数=1
[i]=2
=>i=2<代码>[i]=((i)*2)
=>i=4。在vb.net中,方括号有其含义,但在本上下文中,此含义不会修改
i
的类型或值。另一方面,括号在vb.net中用作索引器。以这种方式在赋值的左侧使用的是C#
inti
((i))=1=>i=1,而
[i]=2
=>i在此上下文中不存在。vb.net
Dim[Integer]作为Integer=1
是有效的,在C#
int[int]
int(int)
中是无效的。每个编译器执行与语言要求相关的规则。在赋值中,vb.net看起来可能比通常看起来更严格,因为赋值运算符和相等比较器是相同的,所以应用于标识符/变量分类和标识的规则不是自由形式的。@Jimi抱歉,我不完全理解您的评论。关于
=
运算符含义的重载,您是对的。我不认为这是问题所在,但很可能是。
=
运算符的双重含义意味着必须解释实际使用。解释过程意味着定义运算符左侧内容的规则必须比人们想象的更严格地执行(主要是因为许多vb.net程序员不使用选项Strict/Explicit)。括号用作索引器。如果在这种情况下,他们的存在没有其他理由,那么就不能假设他们是出于奇特的原因而存在的。解释中的歧义更好(缺少索引元素?)通过语法错误解决。@Jimi Right。我不知道VB解析器的内部结构,但我高度怀疑上述内容是否会运行到索引器的代码路径中。大多数解析器的工作方式是,索引器代码路径只有在左手前面的标记(索引器表达式的左手边)使这成为可能时才会触发。但事实并非如此。这几乎肯定会被解析为è圆括号表达式›。
Sub ChangeMe(ByRef x As Integer)
    x += 1
End Sub

Dim x = 1
ChangeMe(x)   ' x = 2
ChangeMe((x)) ' still x = 2