Select Case True

Select Case True

居里长安 发布于 2021-11-24 字数 198 浏览 707 回复 9 原文

Apparently this used to be a way in VB6 and VBA to short circuit and execute the first true case:

Select Case True
End Select

Is this still in use (VB.NET) ?

如果你对这篇文章有疑问,欢迎到本站 社区 发帖提问或使用手Q扫描下方二维码加群参与讨论,获取更多帮助。

扫码加入群聊

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(9

风和你 2022-06-07 9 楼

After reading this thread, it appears that the primary argument for Select Case True is readability. Is this enough? When I first saw the construct used like this in VB.NET, I had to read over it a few times to make sure I'd got the gist of it, but still thought along the same lines as RolandTumble, above. So even readability comes at a slight cost. Everyone knows what an If...ElseIf...End If statement is and why it's there. Short circuiting can be aided using AndAlso or OrElse, and complexity is purely down to the code and coder involved.

Even If statements can be optimised. What's the point in asking the obvious (whether your value = True). I was once asked what the following did by a coder working with us...

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

The use of the Select Case True structure also feels like you're moving the focus or the comparison emphasis away from the actual Select Case line and into the Case statements, as odd as that may sound.

笨笨の傻瓜 2022-06-07 8 楼

Another reason for using the construct SELECT CASE TRUE is when your case statements evaluate to a boolean value. The SELECT CASE needs to have all cases evaluate to the same data type as the control. If you are looking at a string data type, then all of the case statements need to be strings as well.

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

However if you are comparing partial strings using the LIKE operator then your case data type becomes boolean which will not match the string control. The following code will not work:

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

In order to use wildcards (and thus have boolean case outcomes) you have to have a boolean control value, thus the structure needs to be:

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

I suppose you could use IF...ELSEIF

IF [string] LIKE "*1" AND [string] LIKE "*2" THEN
    [do a thing]
ELSEIF [string] LIKE "*3"
    [do another thing]
END IF

Personally I find the SELECT CASE is easier to use and read when there are more than three options. I use IF...ELSE and IF...ELSEIF when I have to evaluate two or three different options (>, =, <) or if I am testing a value for a specific range of 'valid' entries. If instead the entry has more variety and I need to determine which of ten possibilities has happened the SELECT CASE is a much easier construct to use as it eliminates the need for multiple OR statements.

断桥再见 2022-06-07 7 楼

You can define Equals Operator on any Wrapper Type.
Then you can use Wrapper type on Select Case.

Sample 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

Now you can use _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

About Performance. Release Code is optimized. Wrapper has no performance penalty.

我最亲爱的 2022-06-07 6 楼

Do you mean something like this?

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

In which, the program would write 2...if that's what you're asking, then yes, that is still around in VB.NET

淡看悲欢离合 2022-06-07 5 楼

Select Case is a powerful operator by itself. But even though Select Case True is still supported, it is better to be avoided for maintainability perspective. You always have to justify the need. If needed badly, you can even use DoEvents and GoTo. For the accepted answer, it could have been written like this instead:

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
鲜肉鲜肉永远不皱 2022-06-07 4 楼

There is a lot of confusion on this topic, but to answer the OPs question: Yes, logical evaluation is the same in VB.Net as it is in VB6 as it is in VBA. http://support.microsoft.com/kb/817250

To take advantage of the Select Case optimization technique you use Select Cases inherent syntax to avoid the use of the Logical Operators And, Or, Xor, etc. It is these operators that do have Short Circuit evaluation.

Consider this example:

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

The Select Case version will only run A. The If-Block will run both. This is not If statement's fault, rather it is the fault of the And operator. If you prefer, you can structure the If Statement to short circuit like this:

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

And B will not run. It's all just a matter of style.

The important thing to know is that what you are avoiding is the And/Or/Xor Operators not the If-Blocks. If you like the Select Case version of the If-Block better... More power to you:)

彼岸花ソ最美的依靠 2022-06-07 3 楼

Others have already answered that actual question, but I just want to chime in that I use this construct fairly frequently. I think it's often the most readable way of simultaneously testing two boolean conditions:

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

I admit that part of why I find it easily readable is that I do use it, and that I do recall having to parse it the first time I saw it--but once successfully parsed, my reaction was "That's brilliant!"

终止放荡 2022-06-07 2 楼

I'm not sure how this construct offers any advantages over the following:

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

The above structure is short-circuiting, and I don't have to try to work out what it does as it's a standard construct.

怎樣才叫好 2022-06-07 1 楼

This syntax is often used instead of an If...ElseIf statement. Some people find it a little easier to read. For example:

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

The answer is that yes, this still works in VB.NET. Just take care with when you use it, because it's not a "standard programming construct" and may be unfamiliar to people that have to maintain your code in the future.