Tuesday, November 17, 2009

.NET Object Collections Using Generics 101

Since the .NET Framework 2.0, we have had the ability to use Generics from the System.Collection.Generic namespace to create a strongly typed list of objects. Some might be saying, "Well what is that?" It is a great way to take a single instance of an object and add it to a 'list' where additional object instances can be added as well. It is basically an ArrayList of objects.

So the next question might be, "Well why do I need that?" Think of another common way to organize relation data using a non-strongly type traditional DataSet. A DataTable within a DataTable has rows and columns. Typically to reference a value within that DataSet we might have a line of code similar to the following:


Dim MyValue As String = ds.Tables("MyTable1").Rows(0).Item("FirstName").ToString()

Now that does work, however that is a lot of hardcoding and can be difficult to keep up with. Especially on a multi developer project. Imaging trying to remember all of those column names if that DataSet was passed back to the UI to be bound to a control or populate others. This is where a nice entry point into a list of objects arises. Of course developers could comment on the several reasons using lists of objects is advantageous, but I will take the approach to a developer that is using native ADO.NET objects to do the same thing.

I will provide a simple example to help beginners understand how to put together a list of objects using the 'List(of T)' class. First let's start by looking at the following simple class named 'Customer':


Public Class Customer

Private mFirstName As String = String.Empty
Private mLastName As String = String.Empty
Private mID As Integer = 0

Public Sub New()
'Default class Constructor
End Sub

Public Property FirstName() As String
Get
Return mFirstName
End Get
Set(ByVal value As String)
mFirstName = value
End Set
End Property

Public Property LastName() As String
Get
Return mLastName
End Get
Set(ByVal value As String)
mLastName = value
End Set
End Property

Public Property ID() As Integer
Get
Return mID
End Get
Set(ByVal value As Integer)
mID = value
End Set
End Property

Public Function ShowFullName() As String
'Simple class method; just for show
Return Me.FirstName + Me.LastName
End Function

End Class

Now at this point we may have received multiple rows back from the database containing data with the elements mapping to the properties above. Previously, we could have placed this data into a DataSet to pass back to the UI as mentioned before. This time we are going to build up a list of objects to use. Now in this case you may still have used an ADO.NET DataAdapter to get the data from a stored procedure and it is currently in a DataTable object. No problem, now is the time to place that data into an object instance (1 DataRow = 1 Object of type Customer) and then add that to the list. Let's take a look how that is done below:


'Create an Customer Object
Dim MyCustomer As New Customer()
'Create a List of objects of type Customer
Dim MyCustomerLst As New List(Of Customer)
'Iterate through the data returned in the DataTable
For Each dr As DataRow In dt.Rows

'Create a new instance of the Customer object to place this iterations values
MyCustomer = New Customer()

'Add the data to the object's properties
If Not IsDBNull(dr("FirstName")) Then MyCustomer.FirstName = dr("FirstName")
If Not IsDBNull(dr("LastName")) Then MyCustomer.LastName = dr("LastName")
If Not IsDBNull(dr("CustomerID")) Then MyCustomer.ID = dr("CustomerID")

'Add the single object instance created above to the 'List' of objects
MyCustomerLst.Add(MyCustomer)
Next

At this point the object collection named 'MyCustomer' can be passed around your application's layers as a type of 'List(of Customer)'. For example take a look to the following method that takes the list as a parameter, and then loops through it to use its values:


Public Function GenerateCustomerList(ByVal CustomerLst As List(Of Customer)) As String

Dim sb As New StringBuilder

'Iterate through each 'Customer' object instance in the List(of Customer) passed into method:
For Each SingleCustomer As Customer In CustomerLst

'Build a String in the format of: John Smith ID: 1234
sb.AppendLine(SingleCustomer.FirstName + " " + SingleCustomer.LastName + " ID: " + SingleCustomer.ID.ToString())

Next

'Return the appended String
Return sb.ToString()

End Function

So as you can see we were able to iterate through the object collection and being able to refer to the values by object property name rather than a hardcoded value representing the original column named returned from the database. One might say in the example above that we did at one point reference the column name when adding the data to the 'Customer' object instance. Yes, that is true but with this methodology you need only to reference it once and the location of that reference is typically at a low level either in the DAL or at the bottom of the BLL depending on your design. Therefore, if there were database changes that affected those names, they could be changed in one place rather than scattered throughout the UI and entire application.

Passing around a list of objects is much preferable to passing around traditional ADO.NET objects in many situations. Also, there are other types that may have been used similarly that could also be replaced using object collections. An example could be an Array or ArrayList. In fact performance wise, object collections are very good. Read the following excerpt from the MSDN:

"In deciding whether to use the List(Of(T)) or ArrayList class, both of which have similar functionality, remember that the List(Of(T)) class performs better in most cases and is type safe."

There are so many uses for a list of objects, and this entry was just to describe one usage and to provide the developer new to using the List(of T) class some ideas on how they may expand on it. Once you begin to harness the power of OOP and the basic component of it: the class, you will discover an entire new set of powerful tools the .NET Framework offers as discussed here using a List(of Customer).

***UPDATE*** You can imporve this code one step further by using LINQ to populate the list of objects directly rather than manually looping through each DataRow. To see the code look the post of mine from the link below:

How To: Populate a List of Objects from a DataSet Using LINQ

Tuesday, November 10, 2009

How To: Sort Items in an ASP.NET ListBox Control

The need may arise in an ASP.NET application to have several items added to a ListBox by the user at runtime. However, the added items may not show up in order (alphabetically, etc.) by default. The following easy to implement method will take in a ListBox control and sort the items in it. This is a perfect method to create as 'Shared' (VB.NET) or 'Static' (C#) in a Utilities class that is easily accessible.

The work is done by copying the ListBoxItems out of the ListBox and into a List(of ListItem) object collection. This secondary collection can then be manipulated via a 'Comparison' delegate with the address of a method that will compare the (2) items and return them in order. The ordered List of objects is then added back to the original control after being cleared, and the result is having the items in order.

All that the caller needs to do is pass the ListBox control in as a parameter. This could possibly be called on PostBack when the item is added, or maybe upon some other user interaction that calls this method. Another idea might be to use an AJAX UpdatePanel around the ListBox to asynchronously postback to sort the items without a full postback.

Here are the (2) methods needed to sort the ListBox control:


Public Shared Sub SortListBox(ByVal lbxId As ListBox)

Dim t As New List(Of ListItem)()
Dim compare As New Comparison(Of ListItem)(AddressOf CompareListItems)

'Iterate through each ListItem in the Listbox, and add them to the 'List' object
For Each lbItem As ListItem In lbxId.Items
t.Add(lbItem)
Next

'Sort the List
t.Sort(compare)

'Clear the Listbox passed in, and add the sorted list from above
lbxId.Items.Clear()
lbxId.Items.AddRange(t.ToArray())

End Sub

Public Shared Function CompareListItems(ByVal li1 As ListItem, ByVal li2 As ListItem) As Integer

'Return the strings in order that have been compared:
Return [String].Compare(li1.Text, li2.Text)

End Function


And here is an example of calling the method above to sort the ListBoxItems:


'Sort the ListBox control items on the .aspx page
SortListBox(Me.lbxMyItems)

That's all you need to sort the ListBox control. You could also easily change the 'CompareListItems' method to compare the items other than by 'String' which will ultimately make the items appear in alphabetical order. If you did this you may want to overload or extend the original method so that it could be called to sort the items in various ways.

Monday, November 2, 2009

Tools for Converting C# code to VB.NET (or vice versa) and a little => ... Function(), Lambdas too

This seems to be common knowledge for the majority of .NET developers that need help converting C# code to VB.NET or the other way around, but from time to time I still see a new developer to the community that does not know of the avaliable tools to help with this. I also have seen that even some of the more seasoned developers are unaware that there is more than (1) site avaliable to help with this conversion process. So without further ado, here are (3) sites with brief descriptions that will help users conver C# to VB.NET code:

  1. developerFusion's Convert C# to VB.NET - This is probably the most well know site and referenced most often. I typically start with this one: http://www.developerfusion.com/tools/convert/csharp-to-vb/
  2. Code Converter Provided by Telerik - This is another great and stable converter online. I typically go to this one if the code to convert is complex or there were any issues with the converter: http://converter.telerik.com/
  3. KamalPatel.Net - Convert C# to VB .NET - Several years ago I used this one as the defacto converter, but somewhere along the lines the code I was converting was getting too complex, or the site was not upkept anymore because it shows issues converting often. I now come here lastly: http://www.kamalpatel.net/ConvertCSharp2VB.aspx

Now, one of the issues all the converters seem to have issue with is .NET Lambda Expressions. Recently, I have found several powerful code snippets in C# including Labmda expressions that none of the converters would convert properly. This code will need a little extra help in getting it converted. Below I have a brief example of a C# Labmda expression and the equivelent VB.NET code that I had to modify. Hopefully, this code will help guide readers to get started with a proper conversion of Lambda expressions.


The C# version:


.Aggregate(new StringBuilder(), (sb, node) => sb.Append(node.ToString()), sb => sb.ToString());

The VB.NET version:


.Aggregate(New StringBuilder(), Function(sb, node) sb.Append(node.ToString()), Function(sb) sb.ToString())

Both code examples take use of passing values to a function to shorthand the return, however in VB.NET the syntax is more explicit with the 'Function' statement being required. A good reference for Lambda expressions for each language can be found below.


Lambda Expressions (VB.NET):
http://msdn.microsoft.com/en-us/library/bb531253.aspx

Lambda Expressions (C#):
http://msdn.microsoft.com/en-us/library/bb397687.aspx

This was by no means a full entry on .NET Lambda expressions, but I just wanted to briefly highlight some of the differences syntactically between the (2) languages, and where the converters may have issue with more complex code.