4
\$\begingroup\$

I have a select case that checks against a string variable. It's starting to get large and I am wondering if there is a better way of doing this?

Here is a sample of the Select Case statement:

Select Case Param.ToLower
    Case "dashboard_home_vm"
        Return _Locator.DashboardHome_VM
    Case "job_list_vm"
        Return _Locator.JobList_VM
    Case "job_add_vm"
        Return _Locator.JobAdd_VM
    Case "client_add_vm"
        Return _Locator.ClientAdd_VM
    Case "client_list_vm"
        Return _Locator.ClientList_VM
    Case "client_report_vm"
        Return _Locator.ClientReport_VM
    Case "employee_add_vm"
        Return _Locator.EmployeeAdd_VM
    Case "employee_certification_vm"
        Return _Locator.EmployeeCertification_VM
    Case "employee_list_vm"
        Return _Locator.EmployeeList_VM
    Case "employee_report_vm"
        Return _Locator.EmployeeReport_VM
    Case "employee_role_vm"
        Return _Locator.EmployeeRole_VM
    Case "employee_timeslip_vm"
        Return _Locator.EmployeeTimeslip_VM
    Case "product_add_vm"
        Return _Locator.ProductAdd_VM
    Case "product_category_vm"
        Return _Locator.ProductCategory_VM
    Case "product_list_vm"
        Return _Locator.ProductList_VM
    Case "product_type_vm"
        Return _Locator.ProductType_VM
    Case "product_unit_vm"
        Return _Locator.ProductUnit_VM
    Case "tracking_stock_vm"
        Return _Locator.TrackingInStock_VM
    Case "tracking_list_vm"
        Return _Locator.TrackingList_VM
    Case "tracking_site_vm"
        Return _Locator.TrackingOnSite_VM
    Case "vendor_add_vm"
        Return _Locator.VendorAdd_VM
    Case "vendor_list_vm"
        Return _Locator.VendorList_VM
    Case "vendor_report_vm"
        Return _Locator.VendorReport_VM
    Case Else
        Return Nothing
End Select

This actual list will be about 50 - 80 comparisons. Is this the fastest way to do this or is there a better way?

\$\endgroup\$
12
\$\begingroup\$

A classic solution to this problem is to use a data table - in your case probably in form of a dictionary. It depends of what type your values are - I assume they are some sort of view models? I'm also going to assume they have a common base class:

One time setup:

Dim dict As New Dictionary(Of String, ViewModelBase)
dict.Add("dashboard_home_vm", _Locator.DashboardHome_VM)
...

You can look them up simply by

Dim vm As ViewModelBase
If (dict.TryGetValue(Param.ToLower, vm)) Then
    return vm
End If
return Nothing

Adding a new view model would be achieved by simply adding a new entry to the dictionary.

\$\endgroup\$
1
  • \$\begingroup\$ awesome, I knew there had to be cleaner way, also bonus points for correctly guessing that I was referring to view models. You even got the base class name right! \$\endgroup\$
    – J King
    Nov 22 '13 at 0:13
2
\$\begingroup\$

A dictionary is definitely the way to go, but I think you can improve on /u/ChrisWue's answer.

Since I'm assuming you don't need to change it at runtime, you can use a collection initializer to create it in a single syntactic line. Like this:

Private ReadOnly viewModelLocator As New Dictionary(Of String, ViewModelBase) From {
                    {"dashboard_home_vm", _Locator.DashboardHome_VM},
                    {"job_list_vm", _Locator.JobList_VM},
                    {"job_add_vm", _Locator.JobAdd_VM}
                 }

Initializing it without using the Add method is quicker and allows us to mark this as ReadOnly for clarity. Plus fitting it into a single line means we can initialize it outside of the flow of our constructor.

Don't just call it dict since we already know it's a dictionary from it's type. Use a nice name to describe what this particular dictionary is doing, like viewModelLocator.

When using Dictionary.TryGetValue:

When this method returns, it contains the value associated with the specified key, if the key is found; otherwise, the default value for the type of the value parameter

Since you want to return Nothing if the key is not found and the associated value when it is, and since the default value of your ViewModelBase is Nothing, you don't need to specifically handle the the boolean returned by TryGetValue. You should add another function to read the dictionary that looks like this:

Function GetViewModel(ByVal viewModelName) As ViewModelBase
    Dim vm As ViewModelBase
    viewModelLocator.TryGetValue(viewModelName.ToLower, vm)
    Return vm
End Function

Again, don't call this Param. Use good variable names like viewModelName or something similar.


If you had fewer cases you needed to run through, and you were only returning a single item per case, I think it's slightly more readable to put the entire case on the same line by using the colon (:) as the VB line terminator like this:

Select Case Param.ToLower
    Case "dashboard_home_vm" : Return _Locator.DashboardHome_VM
    Case "job_list_vm" : Return _Locator.JobList_VM
    Case "job_add_vm" : Return _Locator.JobAdd_VM
    '....
End Select
\$\endgroup\$
1
  • \$\begingroup\$ You can mark it as ReadOnly whether or not you use the collection initializer syntax. ReadOnly marks the variable viewModelLocator as not being able to be assigned to after construction. However, it does not make the contents read-only as Add, Remove, etc. can be called on it. That being said, I recommend ReadOnly for that purpose: prevents accidental re-assignment. \$\endgroup\$ Aug 7 '14 at 21:31
-1
\$\begingroup\$

Cant you just use the output of param.tolower after _locator.?

return _locator.(Param.ToLower)

try if that works

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.