为什么VB.NET的"缺失返回值"警告明确排除了"非内在价值类型"?

Hei*_*nzi 7 vb.net language-lawyer roslyn

请考虑以下代码示例:

Function f1() As Object     ' yields warning BC42353
End Function

Function f2() As Int32      ' yields warning BC42353
End Function

Function f3() As DateTime   ' yields warning BC42353
End Function

Function f4() As Guid       ' no warning
End Function
Run Code Online (Sandbox Code Playgroud)

以及以下项目设置:

项目设置

显然,VB.NET在以下三类类型之间有所不同:

  1. 参考类型[例f1],
  2. "内在"值类型(一些显然未记录的值类型的子类别,请参阅什么是内在值类型?)[示例f2和f3],
  3. "非内在"价值类型[例f4],

并为1 + 2提供"缺失返回值"警告,但不提供3(不提供此类编译器选项).

语言设计者决定在这类类型中省略此功能的"非内在价值类型"有什么特别之处?

(我怀疑这是一个深思熟虑的决定,因为(我假设)为所有值类型实现该功能要比检查一些硬编码的"内在"白名单更容易.)

ChD*_*ers 1

鉴于 Roslyn VB 编译器流分析源代码的源代码,特别是在数据流传递中,可以在第 1232 行中找到该源代码,启动决定是否应生成此警告的子程序。请注意,我假设是基于我在存储库中执行的各种搜索。

if 语句从第 1250 行开始,如下所示:

                If type.IsIntrinsicValueType Then


                    Select Case MethodSymbol.MethodKind
                        Case MethodKind.Conversion, MethodKind.UserDefinedOperator
                            warning = ERRID.WRN_DefAsgNoRetValOpVal1
                        Case MethodKind.PropertyGet
                            warning = ERRID.WRN_DefAsgNoRetValPropVal1
                        Case Else
                            Debug.Assert(MethodSymbol.MethodKind = MethodKind.Ordinary OrElse MethodSymbol.MethodKind = MethodKind.LambdaMethod)
                            warning = ERRID.WRN_DefAsgNoRetValFuncVal1
                    End Select


                ElseIf type.IsReferenceType Then


                    Select Case MethodSymbol.MethodKind
                        Case MethodKind.Conversion, MethodKind.UserDefinedOperator
                            warning = ERRID.WRN_DefAsgNoRetValOpRef1
                        Case MethodKind.PropertyGet
                            warning = ERRID.WRN_DefAsgNoRetValPropRef1
                        Case Else
                            Debug.Assert(MethodSymbol.MethodKind = MethodKind.Ordinary OrElse MethodSymbol.MethodKind = MethodKind.LambdaMethod)
                            warning = ERRID.WRN_DefAsgNoRetValFuncRef1
                    End Select


                ElseIf type.TypeKind = TypeKind.TypeParameter Then
                    ' IsReferenceType was false, so this type parameter was not known to be a reference type.
                    ' Following past practice, no warning is given in this case.


                Else
                    Debug.Assert(type.IsValueType)
                    Select Case MethodSymbol.MethodKind
                        Case MethodKind.Conversion, MethodKind.UserDefinedOperator
                            ' no warning is given in this case.
                        Case MethodKind.PropertyGet
                            warning = ERRID.WRN_DefAsgNoRetValPropRef1
                        Case MethodKind.EventAdd
                            ' In Dev11, there wasn't time to change the syntax of AddHandler to allow the user
                            ' to specify a return type (necessarily, EventRegistrationToken) for WinRT events.
                            ' DevDiv #376690 reflects the fact that this leads to an incredibly confusing user
                            ' experience if nothing is return: no diagnostics are reported, but RemoveHandler
                            ' statements will silently fail.  To prompt the user, (1) warn if there is no
                            ' explicit return, and (2) modify the error message to say "AddHandler As 
                            ' EventRegistrationToken" to hint at the nature of the problem.
                            ' Update: Dev11 just mangles an existing error message, but we'll introduce a new, 
                            ' clearer, one.


                            warning = ERRID.WRN_DefAsgNoRetValWinRtEventVal1
                            localName = MethodSymbol.AssociatedSymbol.Name
                        Case Else
                            warning = ERRID.WRN_DefAsgNoRetValFuncRef1
                    End Select
                End If
Run Code Online (Sandbox Code Playgroud)

正如您所看到的,不生成警告的唯一条件是类型 TypeKind 属性等于 TypeParameter。我真的不太了解这些类型,但我假设 .NET 框架中有一些类/类型(GUID 必须是其中之一)具有这种行为方式。

这似乎根本不是一个决定,而是编译器在某些类型中的设计行为。然而,我可以从代码中看到,根据方法的类型(在本例中为函数)添加警告并不难,而不管返回类型,我认为这是最好的做法。

希望这可以帮助。