Logo HeaderGraphic
"... A Yankee in the Land of The Long White Cloud, Aotearoa ..."

C# Needs Select Case (They Finally Gave Us Optional Method Arguments) 

So today I was grousing to myself about the lack of Select Case in C#, and decided to see if anyone out there knew if the C# team was going to give in and admit that, at least when it comes to this programming structure, VB is way better then C++.

For the record, I am now a BIG C# fan (stupid termination character not withstanding), but let’s not let dogma prevent us from speaking heresy.  VB has some things it could teach C#, and in fact has done so already: as of C# 4.0 the C# development team finally cried “uncle” and gave us Optional Arguments on methods (about time).  Talk about cleaner self documenting code!

Anyways, as an old VB programmer one of my favorite programming structures was the VB Select Case.  I’ve heard C# programmers who have never worked in VB say up on the podium in front of people, “the C# switch works just the same and does it as well as the VB Select Case”.  I even heard one talker dare anyone to show him a case where the VB system is better.

So trolling on the message boards, I saw this response to a former VB programmer how to make the C# switch work like in VB.

image
switch(true) in c#

OK, that’s just UGLY.  if you look at the subject line “Re: switch(true) in c#” that’s how I know it was a VB programmer asking. The issue here is that the C# switch can only make it’s branch on a fixed value (not an expression) in the switch, and the case statements must be fixed values as well (no expressions allowed).  VB does not have this restriction, it compares the value of the expression in the Select with the value of the expression in the Case and drops into the first instance where it is true.  The key words are “value of the expression” is allowed in both the Select AND the Case.

So let’s look at the exact same code done in the VB Select

Select Case True
    Case "a" = "b"
        resultString = "1"
    Case "a" = "c"
        resultString = "2"
    Case "a" = "a"
        resultString = "3"
    Case "a" = "d"
        resultString = "4"
    Case Else
        resultString = ""
End Select

Ok you try to tell me that the C# system is just as good as the VB…  In this case VB beats C# hands down for clear concise obvious code.  This is a simple case, let me give you an even more “obvious” one.

Here is some real code I’m working on, don’t worry too much about the specifics of what the code is doing (I took out the meat of the proc, and I still need to do some refactoring), just look at the code processing tree

private string PrepareAliasTextualInsert ( Contact contact ) {

    var contactPage = mSettings.GetSingleValue( "ContactPage" ).ToString( );

    if ( !string.IsNullOrEmpty( contactPage ) ) {

        return FormattedForContactPage( contact.DisplayName , contactPage , contact.Alias );

    } else {

        if ( contact.UseCategoryLinking ) {

            return FormattedForCategoryLink( contact.DisplayName );

        } else {
    
            return FormattedForTag( contact.DisplayName , contact.Alias );

        }

    }

}

Ok, now compare how I could do the same thing in VB

Private Function PrepareAliasTextualInsert(ByVal contact As Contact) As String

    Select Case True

        Case (Not String.IsNullOrEmpty(mSettings.GetSingleValue("ContactPage").ToString()))
            Return FormattedForContactPage(contact.DisplayName, mSettings.GetSingleValue("ContactPage").ToString(), contact.Alias)

        Case contact.UseCategoryLinking
            Return FormattedForCategoryLink(contact.DisplayName)

        Case Else
            Return FormattedForTag(contact.DisplayName, contact.Alias)

    End Select

End Function

I think the VB reads better.

How about this example,

Imagine you have to process bonuses for employees:

  • Employees either have fixed bonus or proportional bonus
  • proportional bonus have 3 types of categories
    • hours worked (standard line worker)
      • if worker has been with company less then 1 year they don’t get a bonus
    • profits earned for company (corporate officers - executives)
    • profit earned by department (department managers)

Let’s see the VB implementation first

Private Function PrepareEmployeeBonus(ByVal employee As Employee) As Double

    Select Case True

        Case employee.HasFixedBonus
            Return FixedBonusCalculation(employee)

        Case employee.IsCorporateOfficer
            Return CompanyProfitBonusCalculation(employee)

        Case employee.IsDepartmentManager
            Return DepartmentProfitBonusCalculation(employee)

        Case employee.YearsOfEmployment > 1
            Return LineWorkerBonusCalculation(employee)

        Case Else
            Return 0

    End Select

End Function

I think that reads REALLY nicely, now let’s see the C# (Please note, there is no way to process that in a switch unless you use the ugly method from that feedback forum example at the top that I just can’t see anyone trying to justify as being easy to read):

private double PrepareEmployeeBonus ( Employee employee )
{
    if ( employee.HasFixedBonus )
    {
        return FixedBonusCalculation( employee );
    }
    else
    {
        if ( employee.IsCorporateOfficer )
        {
            return CompanyProfitBonusCalculation( employee );
        }
        else if ( employee.isDepartmentManager )
        {
            return DepartmentProfitBonusCalculation( employee );
        }
        else
        {
            if ( employee.YearsOfEmployment > 1 )
            {
                return LineWorkerBonusCalculation( employee );
            }
			return 0;
        }
    }
}

ok, so is that the best I can make it look in C#, well no, you could do this:

		private double PrepareEmployeeBonus ( Employee employee )
		{
			if ( employee.HasFixedBonus )
			{
				return FixedBonusCalculation( employee );
			}
			else
			{
				return PrepareProportionalBonus( employee );
			}
		}

		private double PrepareProportionalBonus ( Employee employee )
		{
			if ( employee.IsCorporateOfficer )
			{
				return CompanyProfitBonusCalculation( employee );
			}
			else if ( employee.isDepartmentManager )
			{
				return DepartmentProfitBonusCalculation( employee );
			}
			else
			{
				return PrepareLineWorkBonus( employee );
			}
		}

		private double PrepareLineWorkBonus(Employee employee)
		{
			if ( employee.YearsOfEmployment > 1 )
			{
				return LineWorkerBonusCalculation( employee );
			}
			return 0
		}

That doesn’t look any better to me.

Face it C# guys, when it comes to the switch statement we are working with a really weak substitute.  Dump the C++ and channel your inner VB!

 
Posted on 18-Nov-09 by Matthew C. Hintzen
Bookmark this post with:        
Tags: