Blog Map
[Table of Contents] [Next Topic] [Blog Map] This blog is inactive. New blog: EricWhite.com/blog
The following example (from the previous topic on anonymous types) shows projection of a collection of anonymous types:
Dim custList() As Customer = { _ New Customer With { _ .Name = "Bob", _ .Address = "123 Main Street, Seattle, WA 98111", _ .Phone = "555-1234" _ }, _ New Customer With { _ .Name = "Bill", _ .Address = "555 Center Street, Tacoma, WA 97158", _ .Phone = "555-9999" _ } _}Dim newCustList = _ custList.Select( _ Function(c) New With { _ .UCName = c.Name.ToUpper, _ .UCAddress = c.Address.ToUpper _ } _ )For Each c In newCustList Console.WriteLine(c.UCName)Next
However, one problem with this code is that as written, we can't move the query into its own method.
A different approach, which I like more, is to define a named type for the tuple. In C#, a convenient syntax is the automatic properties syntax, which allows you to define a type in a very few lines. VB doesn’t have an equivalent feature. However, you can gain the same expressiveness and succinctness by using public fields. If you are using these types only for tuples, and only within a limited scope, I don’t have a problem with this approach. Using this approach, you can define a class with n fields in n+2 lines of code. The syntactic noise is kept to a minimum. Depending on the circumstances, you can declare the tuple class as a nested class.
One of the characteristics of dynamic languages is the ability to add new properties to a tuple type very easily. This characteristic is shared by VB when projecting using anonymous types. However, I find that I have the same type of experience when using named types in the fashion described in this topic. I don't find it particularly onerous to add new fields to the tuple type. I have a little macro that creates one for me, and all I need to type are the type and the name. The malleability of tuple types is nearly as good as when using a dynamic type, except that you get strong typing, and a good Intellisense experience in VS.
Consider the following code, where the tuple is defined using a private named class, and the query and projection are refactored into a separate method.
Public Class Customer Private m_name As String Private m_address As String Private m_phone As String Public Property Name() As String Get Return m_name End Get Set(ByVal value As String) m_name = value End Set End Property Public Property Address() As String Get Return m_address End Get Set(ByVal value As String) m_address = value End Set End Property Public Property Phone() As String Get Return m_phone End Get Set(ByVal value As String) m_phone = value End Set End PropertyEnd Class Module Module1 Private Class UCCustomer Public UCName As String Public UCAddress As String Public Phone As String End Class Private Function ProjectUC(ByVal source As IEnumerable(Of Customer)) As IEnumerable(Of UCCustomer) Return source.Select(Function(c) New UCCustomer With { _ .UCName = c.Name.ToUpper, _ .UCAddress = c.Address.ToUpper _ }) End Function Sub Main() Dim custList() As Customer = { _ New Customer With { _ .Name = "Bob", _ .Address = "123 Main Street, Seattle, WA 98111", _ .Phone = "555-1234" _ }, _ New Customer With { _ .Name = "Bill", _ .Address = "555 Center Street, Tacoma, WA 97158", _ .Phone = "555-9999" _ } _ } Dim newCustList = ProjectUC(custList) For Each c In newCustList Console.WriteLine(c.UCName) Next End SubEnd Module
Notice in the above code that the object initializer for the tuple type is nearly identical to the object initializer when projecting an anonymous type. The only difference is the naming of the type in the initializer.
When writing queries on the fly, anonymous types are handy.
Sometimes I'll expose the nominal tuple type as a public class, and it becomes part of the programming interface to the classes and methods that contain my FP code. For an example of this approach (in C#), see Open XML SDK and LINQ to XML.
[Table of Contents] [Next Topic] [Blog Map]
Of course, with VB10, you will be able to define full-blown properties with single lines instead of needing to use public fields.