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?
3 Answers 3
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.
-
\$\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– J King2013年11月22日 00:13:28 +00:00Commented Nov 22, 2013 at 0:13
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
-
\$\begingroup\$ You can mark it as
ReadOnly
whether or not you use the collection initializer syntax.ReadOnly
marks the variableviewModelLocator
as not being able to be assigned to after construction. However, it does not make the contents read-only asAdd
,Remove
, etc. can be called on it. That being said, I recommendReadOnly
for that purpose: prevents accidental re-assignment. \$\endgroup\$Jesse C. Slicer– Jesse C. Slicer2014年08月07日 21:31:26 +00:00Commented Aug 7, 2014 at 21:31
Cant you just use the output of param.tolower after _locator.?
return _locator.(Param.ToLower)
try if that works