0

In a Select...Case statement, is there a way to skip cases based on a precondition?

What I'm doing now, using an incredibly stupid example:

Private Sub PrintNumbers(includeEvenNumbers As Boolean, includeOddNumbers As Boolean)
    For number As Integer = 0 To 9
        Select Case number
            Case 0, 2, 4, 6, 8
                If includeEvenNumbers Then
                    Console.WriteLine(number)
                End If
            Case 1, 3, 5, 7, 9
                If includeOddNumbers Then
                    Console.WriteLine(number)
                End If
        End Select
    Next
End Sub

Sometimes I'll even write my cases inside out:

Private Sub PrintNumbers(includeEvenNumbers As Boolean, includeOddNumbers As Boolean)
    For number As Integer = 0 To 9
        Select Case True
            Case includeEvenNumbers
                If number Mod 2 = 0 Then
                    Console.WriteLine(number)
                End If
            Case includeOddNumbers
                If number Mod 2 <> 0 Then
                    Console.WriteLine(number)
                End If
        End Select
    Next
End Sub

What I'd really like to do instead:

Private Sub PrintNumbers(includeEvenNumbers As Boolean, includeOddNumbers As Boolean)
    For number As Integer = 0 To 9
        Select Case number
            Case 0, 2, 4, 6, 8 When includeEvenNumbers
                Console.WriteLine(number)
            Case 1, 3, 5, 7, 9 When includeOddNumbers
                Console.WriteLine(number)
        End Select
    Next
End Sub

Notice that I used the When keyword, which is currently only used in Try...Catch blocks.

Can this be done? Who do I talk to to make this happen?

EDIT (1/2)

What's important is that this code would first evaluate When <expression>. Only if that evaluates to True, it would go on to evaluate the Case <expression>.

The main reason why I want to do this is because I'd like to write cases where the test condition throws an exception if the circumstances are right (or wrong, depending on how you look at it). I'd like to skip those cases if the precondition is true.

EDIT (2/2)

It's pretty clear by now that what I'm asking for is not possible in the current iteration of VB. So I searched for a place to submit feature requests to the .NET development team, then found out they have a uservoice platform.

Long story short: if you'd like to see this implemented, tap the vote button on this page: https://visualstudio.uservoice.com/forums/121579-visual-studio/suggestions/4274712-add-when-keyword-support-to-select-case-stat

Steven Liekens
  • 13,266
  • 8
  • 59
  • 85
  • probably I did not catch your point precisely - why not use linq instead of Select-Case statement? – Rex Aug 07 '13 at 02:25
  • 1
    Another option is to simply skip the `Select`, and do something like `If includeEvenNumbers AndAlso number Mod 2 = 0 Then Console.WriteLine(number) Else If includeOddNumbers AndAlso number Mod 2 <> 0 Then Console.WriteLine(number) End If`? – Tim Aug 07 '13 at 02:53
  • @Rex how would you fit linq into this? – Steven Liekens Aug 07 '13 at 03:18
  • @Tim that's actually what I'm doing in my real code. Not the dumb example above. I just don't like having 3+ `ElseIf`s in places where you would otherwise use a switch, but can't. – Steven Liekens Aug 07 '13 at 03:23

2 Answers2

0

example of linq:

    Dim condition As Predicate(Of Integer) = Nothing
    If includeEvenNumbers Then
        condition = Function(x) x Mod 2 = 0
    Else
        condition = Function(x) x Mod 2 = 1
    End If

    For Each item In Enumerable.Range(0, 8).Where(condition)
        ' do what ever you like here...
    Next

EDIT: to make it simpler:

For Each item In Enumerable.Range(0, 8).Where(Function(x) x Mod 2 = If(includeEvenNumbers, 0, 1))
    ' do what ever you like here...
Next
Rex
  • 2,130
  • 11
  • 12
  • I can see how linq solves this specific problem in less code, but if the problem changes then I can start all over again. – Steven Liekens Aug 07 '13 at 03:41
  • yes, it could become very complicated if you have many conditions. but if you have a lot of conditions doing different stuff, why not wrap each task in a different class with different criteria? generally you will have a collections of tasks with specified criteria and then pass the collection of data as a context throughout the tasks... believe it will be more maintainable, isn't it? – Rex Aug 07 '13 at 03:55
0

By using an enum instead of 2 booleans you only need one if statement to accomplish a 2 condition check. Something like this:

Public Enum Include
    Odd = 1
    Even = 2
    Both = 0
End Enum
Private Sub PrintNumbers(includenumbers As Include)
    For I = 1 To 10
        If includenumbers = Include.Both OrElse I Mod 2 = includenumbers Mod 2 Then
            TextBox2.AppendText(I.ToString)
        End If
    Next
End Sub

You would call it like this:

PrintNumbers(Include.Odd)
tinstaafl
  • 6,908
  • 2
  • 15
  • 22
  • Good, although that doesn't account for the case where a user wants to print both even and odd numbers. But anyway, I didn't mean to put that much emphasis on solving the example I gave. I only wrote it to demonstrate where I was going with this. – Steven Liekens Aug 07 '13 at 15:23
  • I added code to do both. I should have been more verbose in my answer. While this does solve your example, it does also demonstrate that when a certain construct can't do the job you want, it might be time to step back and re-examine your approach. This particular approach will work for a great many situations where you need several different conditions met. – tinstaafl Aug 07 '13 at 15:35
  • I fully agree, but that's besides the point I'm trying to make. I've already proven in the first two code blocks that `Select...Case` can handle this particular job. The third block is just shorter, easier to understand and would probably perform better if used correctly. – Steven Liekens Aug 07 '13 at 16:18