Visual Basic 9.0 Features Without C 3.0 Counterparts


Visual Basic 9.0 Features Without C# 3.0 Counterparts

Visual Basic 9.0 has some features that do not have an equivalent counterpart in C# 3.0. These features are partially related to LINQ. XML support has a big impact only if you use LINQ to XML. Dynamic interfaces and dynamic identifiers are not necessary to support LINQ from Visual Basic 9.0.

XML Support

Visual Basic 9.0 is a language that implements a particular syntax support for LINQ to XML, consisting of XML literals and late binding over XML. To describe these features, we will use some classes that are part of LINQ to XML: XDocument, XElement, and XAttribute. We will cover these classes in more detail in Chapter 6, “LINQ to XML.” For the purpose of describing XML support, it is sufficient to know that these classes represent an XML document, element, and attribute, respectively.

XML Literals

In Visual Basic 9.0, an XML literal is considered an expression. If you want to assign a value to an object representing an XML tree, you can simply write that value as an assigned expression, as shown in Listing 3-23.

Listing 3-23: XML literal used as a constant

image from book
  Dim ourBook As XElement ourBook = _     <Book Title="Introducing LINQ">         <Author>Marco Russo</Author>         <Author>Paolo Pialorsi</Author>     </Book> 
image from book

We have assigned to ourBook an XElement instance named Book that has an attribute Title containing “Introducing LINQ” and two inner Author elements containing our names.

The code in Listing 3-23 is translated by the compiler into the following calls:

 Dim book As XElement book = New XElement("Book", _             New XAttribute("Title", "Introducing LINQ"), _             New XElement("Author", "Marco Russo"), _             New XElement("Author", "Paolo Pialorsi"))

Important 

As we said before, XML literals are expressions in Visual Basic 9.0. These expressions do not require a line continuation when defined across multiple lines. More important, either an underscore character or a comment in an XML literal is considered part of the XML and not a line continuation or a comment. This is a big exception against Visual Basic syntax. The end of the expression is defined by the closing tag matching the initial tag.

As usual, we can infer the variable type by placing the initial assignment into the declaration. In the next assignment, we can also see an XML literal defined in a single line:

 Dim book = <Book Title="Introducing LINQ"></Book>

It is important to understand that XML literals are converted into method calls by the compiler. The compiler expects a valid XML syntax. An invalid XML literal produces a compiler error. As you can see in Listing 3-24, the XML literal assigned to a has an invalid Title attribute (it’s missing a "), and the one assigned to b has a missing closing tag (it should be </Book> instead of <Book>).

Listing 3-24: Invalid XML literals

image from book
  Dim a = <Book Title="Invalid Title></Book> ' Error Dim b = <Book Title="Good Title"><Book>    ' Error 
image from book

Visual Basic 9.0 leverages XML literals, thereby enabling the calls for other expressions. In other words, an XML literal can be an expression that will be evaluated at execution time and not only a constant in the code. For example, imagine that we want to generate an XML literal dynamically for a book and use a string to assign the book title attribute. To do that, we need to “break” the XML literal with a regular Visual Basic 9.0 expression, using the special <%= and %> tags. The code in Listing 3-25 shows how to assign attributes and element content with regular Visual Basic 9.0 expressions.

Listing 3-25: XML literal in a dynamic expression

image from book
  Dim bookTitle = "Introducing LINQ" Dim author1 = "Marco Russo" Dim author2 = "Paolo Pialorsi" Dim book = _     <Book Title=<%= bookTitle %>>         <Author><%= author1 %></Author>         <Author><%= author2 %></Author>     </Book> 
image from book

Warning 

Leave a space after <%= tags and before %> tags; otherwise, the compiler cannot interpret the expression correctly.

The <%= and %> tags define a “hole” into an XML literal that embeds an expression, which is evaluated and substituted into the hole at execution time. These holes are placeholders equivalent to the parameters of an XElement, XAttribute, or XDocument constructor. You can place into holes an expression that is valid in those contexts.

For example, we can define in a dynamic way not only the element and attribute content, but also their names, as shown in Listing 3-26. We also use a string concatenation to assign the Authors element, combining two strings with our names, divided by a comma.

Listing 3-26: Dynamic XML tags in an XML literal

image from book
  Dim bookTitle = "Introducing LINQ" Dim author1 = "Marco Russo" Dim author2 = "Paolo Pialorsi" Dim tagBook = "Book" Dim attrName = "Title" Dim tagAuthors = "Authors" Dim book = _     <<%= tagBook %> <%= attrName %>=<%= bookTitle %>>         <<%= tagAuthors %>><%= author1 & ", " & author2 %></>     </> 
image from book

In our opinion, the example in Listing 3-26 is not the best way to use XML literals. Filling the code with angular brackets and “holes” is not the best way to make code readable. The same book assignment is more explicit and clear if written with the code shown in Listing 3-27 (for the sake of brevity, we skipped variable declarations).

Listing 3-27: Dynamic XML tags in explicit method calls

image from book
  Dim book = _       New XElement(tagBook, _           New XAttribute(attrName, bookTitle), _           New XElement(tagAuthors, author1 & ", " & author2)) 
image from book

Note 

We are not saying that you should not use expressions to assign a tag name in an XML literal. Our intention is to emphasize that expressions embedded in XML literals are convenient when the resulting XML structure is immediately understandable. At the extreme, you could define an XML literal without any constant inside (as we did before), but we do not think this is significantly more readable than regular method calls.

If you use an embedded expression to define XML element names, you have to be careful with the syntax required for the closing tag. In such a case, the closing tag must not have the tag name inside. As you can see in Listing 3-28, the closing tag is only </>, without the dynamic tag name defined by the tagElement variable.

Listing 3-28: Closing tag for dynamic XML tags

image from book
  Dim tagElement = "Description" Dim sample = <<%= tagElement %>>Sample element</> 
image from book

A hole in an XML literal can embed just one expression. Because an XML literal is an expression, you can write this apparently useless syntax:

 Dim book = _     <Book Title="Introducing LINQ">         <%= <Publisher>Microsoft Press</Publisher> %>     </Book>

In this case, the Publisher element is an XML literal embedded into a hole of the external Book element, another XML literal. This example is useful for observing an important syntax detail. The <%= tag must have the evaluated expression in the same line; otherwise, it requires a line continuation. The %> tag must be in the same line as the end of the evaluated expression; otherwise, we need a line continuation in the preceding line.

In other words, the following code is not valid:

 Dim book = _     <Book Title="Introducing LINQ">         <%=             <Publisher>Microsoft Press</Publisher>         %>     </Book>

But we can separate code in different lines by using line continuation, as in the following sample. Note that line continuation is always external to XML literals.

 Dim book = _     <Book Title="Introducing LINQ">         <%= _             <Publisher>Microsoft Press</Publisher> _         %>     </Book>

If you want to put more expressions into a single hole, you must define an array of elements. For example, to put two separate Author elements into a single hole, we can enclose a list of XML literals between brackets, as shown in Listing 3-29. Note the use of a line continuation character after the first element in the array initializer.

Listing 3-29: Nested list of XML literals

image from book
  Dim book = _     <Book Title="Introducing LINQ">         <%= { <Author>Marco Russo</Author>, _               <Author>Paolo Pialorsi</Author> } %>     </Book> 
image from book

We just used an array to put a list of Author elements into a Book element. Therefore, we can leverage other methods that generate an IEnumerable object to put a list of XML elements into another XML element.

In the statements shown in Listing 3-30, we use a LINQ query to get the list of authors from an array of people. As you can see, an XML literal can embed a query expression that returns a sequence of XML literals, which are built with another embedded expression that references each row returned from the query.

Listing 3-30: Query embedded into an XML literal

image from book
  Dim team = {New {Name := "Marco Russo", Role := "Author"}, _              New {Name := "Paolo Pialorsi", Role := "Author"}, _              New {Name := "Roberto Brunetti", Role := "Reviewer"}} Dim book = _     <Book Title="Introducing LINQ">         <%= From person In team _             Where person.Role = "Author" _             Select <Author><%= person.Name %></Author> %>     </Book> 
image from book

By combining LINQ syntax and XML literals, you can generate simple and complex XML data structures containing query results in an easy and efficient way.

Late Binding over XML

When you want access to XML data, you probably need to navigate into an object tree that represents the hierarchical structure of the XML document. Visual Basic 9.0 offers some syntax that simplifies this kind of operation-that is, late-binding operations over XML.

We start by considering an XML list of movies. Each movie item must have one Title (as an attribute) and one Director (as an element), plus one list of genres for each movie. The following code shows part of the initialization in our sample code:

 Dim movies = _ <Movies>     <Movie Title="Fight Club">         <Genre>Crime</Genre>         <Genre>Drama</Genre>         <Genre>Thriller</Genre>         <Director>David Fincher</Director>     </Movie>     <!−other movies not shown here --> </Movies>

The first dedicated XML syntax that we show is the child axis. If we write movie.<Genre>, we get all the genres of the chosen movie, as we can see in Listing 3-31.

Listing 3-31: Child axis

image from book
  Dim fightClub = _     (From movie In movies.<Movie> _     Where movie.@Title = "Fight Club" _     Select movie).First() ' Get the first genre Dim firstGenre = fightClub.<Genre>(0).Value ' Corresponds to: firstGenre = fightClub.Elements("Genre")(0).Value Console.WriteLine("First = {0}", firstGenre) ' Display all genres ' Corresponds to: fightClub.Elements("Genre") For Each g In fightClub.<Genre>     Console.WriteLine(g.Value) Next 
image from book

If the query provides only one row, or if we are interested only in the first row of results, we can access the first element of the collection. For example, fightClub.<Genre>(0) allows access to a corresponding XElement instance. If we need the value of an element or an attribute, we need to read the Value property. However, this syntax might return more than one row. In such a case, a loop that iterates over all rows in the sequence might access all of them.

The child axis syntax is translated into a call to Elements, specifying the name of the element as an argument. For syntax details, refer to the comments in Listing 3-31.

You can access an attribute through the attribute axis. If you write fightClub.@Title, you get a string with the value of the attribute, as shown in Listing 3-32.

Listing 3-32: Attribute axis

image from book
  ' Display the Title attribute of Fight Club movie Console.WriteLine(fightClub.@Title) ' Corresponds to: Console.WriteLine(fightClub.Attribute("Title").Value) 
image from book

The attribute axis syntax is translated into a call to Attribute, specifying the name of the attribute as an argument.

The last operation introduced here is the descendants axis. It allows you to get all children of an element, regardless of their position in the hierarchy. You can see in Listing 3-33 that the syntax is similar to the one for the child axis, but there are three dots instead of one.

Listing 3-33: Descendants axis

image from book
  ' List of Directors Dim directors = movies...<Director> For Each director In directors     Console.WriteLine(director) Next 
image from book

In this case, the output of Listing 3-33 (the descendants axis) shows possible duplicates. We could use the Distinct operator to “clean up” the output. We will provide more details about this when we discuss LINQ operators in Chapter 4.

We will further analyze the integration with XML of .NET compilers in Chapter 6.

Relaxed Delegates

In Visual Basic version 8.0 and earlier, if you wanted to bind a method to a delegate, the two signatures (method and delegate) had to be exactly the same. This is not necessary in C#-the method simply needs a “compatible” signature. For example, less specialized types in parameters are allowed. Visual Basic 9.0 removes the previous limitation, and you can now legally write code such as that shown in Listing 3-34.

Listing 3-34: Relaxed delegates

image from book
  Public Delegate Sub EventHandler(ByVal s As Object, ByVal e As EventArgs) Public Class DemoEvent     Public Event Click As EventHandler End Class Module Application     Public WithEvents A As DemoEvent     Sub DemoOnClick(ByVal s As Object, ByVal e As Object) Handles A.Click         Console.WriteLine("Hello World")     End Sub     ' ... End Module 
image from book

In Listing 3-34, we highlighted the line that produces a compilation error in Visual Basic 8.0. To be compiled with Visual Basic 8.0, it should have been written as shown in the following code (in which we have highlighted the changed type of the second parameter):

 Sub DemoOnClick(ByVal s As Object, ByVal e As EventArgs) Handles A.Click

If you do not use the parameters inside the method bound to a delegate, you can skip the whole parameter list from the method declaration. The Handles keyword infers the real signature of the method from the corresponding delegate declaration. In Listing 3-35, you can see an alternative way to write the previous DemoOnClick method. C# does not permit such syntax, because C# does not have an equivalent to the Handles keyword that can be used to infer the missing signature.

Listing 3-35: Relaxed delegates with signature inference

image from book
  Sub RelaxedOnClick2() Handles A.Click     Console.WriteLine("Hello World from") End Sub 
image from book




Introducing Microsoft LINQ
Introducing MicrosoftВ® LINQ
ISBN: 0735623910
EAN: 2147483647
Year: 2007
Pages: 78

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net