【问题标题】:Select Case True选择案例真
【发布时间】:2009-04-27 15:26:53
【问题描述】:

显然这曾经是VB6和VBA中短路并执行第一个真实案例的一种方式:

Select Case True
End Select

这还在使用吗(VB.NET)?

【问题讨论】:

  • 在 VB.NET 中使用 AndAlsoOrElse 短路运算符,而不是 Select Case hack。

标签: vb.net vba vb6


【解决方案1】:

此语法通常用于代替If...ElseIf 语句。有些人觉得它更容易阅读。例如:

Select Case True
    Case testVariable < 0
         Console.Write("You must supply a positive value.")
    Case testVariable > 10
         Console.Write("Please enter a number from 0-10.")
    Case True
         Call DoWork(testVariable)
End Select

答案是肯定的,这在 VB.NET 中仍然有效。使用时请注意,因为它不是“标准编程结构”,将来必须维护您的代码的人可能不熟悉。

【讨论】:

  • 对此发表评论已经很晚了,但我最近偶然发现了这一点,我真的很想知道有些人到底是怎么觉得它更容易阅读的?它比明显的 If/ElseIf 版本更需要打字,而且在逻辑上肯定更不容易阅读。
  • @Dave 因为它解决了你有效嵌套if (a) {Do A} else { if (b) {Do B} else { if (c) {Do C} } } } 等的 if else 问题。这也意味着你的测试用例写在一个整洁的列表中(人眼擅长),而不是而不是嵌套在一个页面中。
  • @MarkRoworth:在 VB 中,你有“ElseIf”,而在 C# 中,你有“else if”。
【解决方案2】:

我不确定这个构造如何比以下内容提供任何优势:

If testVariable < 0 Then
     Console.Write("You must supply a positive value.")
ElseIf testVariable > 10 Then
     Console.Write("Please enter a number less than 10.")
Else
     Call DoWork(testVariable)
End If

上面的结构是短路的,因为它是一个标准结构,所以我不必尝试弄清楚它的作用。

【讨论】:

  • 它没有,但是许多 VB 程序员在最纯粹可读的格式方面犯了错误,并且可以说这个问题正是描述了这种情况。不过,您的阵营中肯定有更多 C 风格的开发人员。另请参阅@RolandTumble。
【解决方案3】:

其他人已经回答了这个实际问题,但我只想说我经常使用这个结构。我认为这通常是同时测试两个布尔条件的最易读的方法:

Dim A As Boolean
Dim B As Boolean
'
'do stuff to set values of A and B
'
Select Case True
  Case A And B
    'something
  Case A And Not B
    'something else
  Case Not A And B
    'you get the picture
  Case Else
    '...
End Select

我承认我觉得它易于阅读的部分原因是我确实使用了它,而且我记得我第一次看到它时不得不解析它——但一旦成功解析,我的反应是“太棒了! "

【讨论】:

    【解决方案4】:

    关于这个主题有很多困惑,但要回答 OP 的问题:是的,VB.Net 中的逻辑评估与 VB6 中的逻辑评估和 VBA 中的逻辑评估相同。 http://support.microsoft.com/kb/817250

    要利用 Select Case 优化技术,您可以使用 Select Cases 固有语法来避免使用逻辑运算符 And、Or、Xor 等。正是这些运算符进行了短路评估。

    考虑这个例子:

    Public Sub Example()
        If A Or B Then
            Beep
        End If
        Select Case True
            Case A, B
                Beep
        End Select
    End Sub
    
    Private Function A() As Boolean
    Debug.Print "A Ran"
        A = True
    End Function
    
    Private Function B() As Boolean
    Debug.Print "B Ran"
        B = False
    End Function
    

    Select Case 版本将只运行 A。If-Block 将同时运行。这不是 If 语句的错,而是 And 运算符的错。如果您愿意,可以将 If 语句构造成这样短路:

    Public Sub Example2()
        If A Then
        ElseIf B Then
            Beep
        End If
    End Sub
    

    B 不会运行。这只是风格问题。

    要知道的重要一点是,您要避免的是 And/Or/Xor 运算符而不是 If 块。如果您更喜欢 If-Block 的 Select Case 版本...为您提供更多功能:)

    【讨论】:

    • 注意可以用OrElse短路,只运行A。
    【解决方案5】:

    Select Casea powerful operator by itself。但是即使Select Case True 仍然受支持,从可维护性的角度来看,最好避免使用。你总是必须证明需要。如果非常需要,您甚至可以使用DoEventsGoTo。对于被接受的答案,它可以这样写:

    Select Case testVariable
      Case Is < 0 : Console.Write("You must supply a non-negative value.")
      Case Is > 10 : Console.Write("Please enter a number from 0-10.")
      Case Else : Call DoWork(testVariable)
    End Select
    

    【讨论】:

    • 挑剔指出,但“0”不是“正值”。 ^^
    • @Hardryv:现在好些了吗? :)
    【解决方案6】:

    你的意思是这样的吗?

     Select Case True
        Case 1 = 0
            Console.Write("1")
        Case 1 = 1
            Console.Write("2")
        Case 2 = 2
            Console.Write("3")
    End Select
    

    在其中,程序将编写 2...如果这是您所要求的,那么是的,在 VB.NET 中仍然存在

    【讨论】:

      【解决方案7】:

      您可以在任何包装器类型上定义等于运算符。 然后你可以在 Select Case 上使用 Wrapper 类型。

      示例包装器。

      Imports System.Runtime.InteropServices
      <DebuggerStepThrough()> Friend Module Util
        Public Function _Is(v As Object) As IsWrapper
            Return New IsWrapper With {.Obj = v}
        End Function
        Public Structure IsWrapper
           Public Obj As Object
           Public Shared Operator =(ByVal a As IsWrapper, ByVal b As Object) As Boolean
               Return a.Obj Is b
           End Operator
           Public Shared Operator <>(ByVal a As IsWrapper, ByVal b As Object) As Boolean
               Return a.Obj IsNot b
           End Operator
        End Structure
      End Module
      

      现在你可以使用 _is(AnyObject):

      Private Sub RbClass_CheckedChanged(sender As System.Object, e As System.EventArgs)
          If DirectCast(sender, RadioButton).Checked = False Then Return
          Select Case _Is(sender)
              Case RbClass : Rb = 0
              Case RbTablePredicate : Rb = 1
              Case RbTableRowFilter : Rb = 2
          End Select
          QueryCtl1_QueryChanged(Nothing, Nothing)
      End Sub
      
      Public Sub Predicate(ByVal PredicateType As Type, ByVal Op As Operadores, ByVal Obj As Object, ByVal CompareOptions As CompareOptions, ByVal Fnc As [Delegate])
         Dim pred As [Delegate] = Nothing
         Select Case _Is(PredicateType)
            Case GetType(Boolean)
                pred = New Predicate(Of Boolean)(Function(v) v)
            Case GetType(String)
                pred = StrPredicate(Op, Obj, CompareOptions)
            Case Else 'Utilizar Generics
                pred = GenericHelper.Builder(PredicateType).Predicate(Op, Obj)
         End Select
         Predicate(pred, Fnc)
      End Sub
      

      关于性能。 发布代码已优化。 Wrapper 没有性能损失。

      【讨论】:

        【解决方案8】:

        使用构造 SELECT CASE TRUE 的另一个原因是当您的 case 语句评估为布尔值时。 SELECT CASE 需要让所有案例评估为与控件相同的数据类型。如果您正在查看字符串数据类型,那么所有 case 语句也必须是字符串。

        SELECT CASE [string]
        CASE "String 1", "String 2"
            [do a thing]
        CASE "String 3"
            [do another thing]
        END SELECT
        

        但是,如果您使用 LIKE 运算符比较部分字符串,那么您的案例数据类型将变为布尔值,这将与字符串控件不匹配。以下代码将不起作用:

        SELECT CASE [string]
        CASE LIKE "*1", "*2"
            [do a thing]
        CASE LIKE "*3"
            [do another thing]
        END SELECT
        

        为了使用通配符(因此有布尔大小写结果),您必须有一个布尔控制值,因此结构需要是:

        SELECT CASE TRUE
        CASE [string] LIKE "*1", "*2"
            [do a thing]
        CASE [string] LIKE "*3"
            [do another thing]
        END SELECT
        

        我想你可以使用 IF...ELSEIF

        IF [string] LIKE "*1" AND [string] LIKE "*2" THEN
            [do a thing]
        ELSEIF [string] LIKE "*3"
            [do another thing]
        END IF
        
        p>本地,当有三个选项时,我发现选择案例更易于使用和读取。当我必须评估两个或三个不同的选项(>、=、

        【讨论】:

          【解决方案9】:

          阅读此线程后,Select Case True 的主要论点似乎是可读性。这够了吗?当我第一次在 VB.NET 中看到这样使用的构造时,我不得不仔细阅读它几次以确保我掌握了它的要点,但仍然按照与 RolandTumble, above 相同的思路进行思考。因此,即使是可读性也要付出一点代价。每个人都知道If...ElseIf...End If 声明是什么以及它为什么存在。使用AndAlsoOrElse 可以辅助短路,复杂性完全取决于所涉及的代码和编码器。

          即使If 语句也可以优化。问显而易见的问题有什么意义(是否是您的value = True)。曾经有人问我,与我们一起工作的编码员做了以下什么...

          Dim isVisible As Boolean
          ....
          If isVisible Then
              ....
          End If
          

          Select Case True 结构的使用也让人感觉您将焦点或比较重点从实际的 Select Case 行移到 Case 语句中,这听起来很奇怪。

          【讨论】:

            猜你喜欢
            • 2018-11-30
            • 2011-01-23
            • 2011-06-10
            • 1970-01-01
            • 1970-01-01
            • 2012-11-07
            • 2023-03-28
            • 2014-02-09
            • 2019-03-28
            相关资源
            最近更新 更多