Visual Basic 14.0 Features

Introduction

Visual Basic 14 is the version of Visual Basic that was shipped as part of Visual Studio 2015.

This version was rewritten from scratch in about 1.3 million lines of VB. Many features were added to remove common irritations and to make common coding patterns cleaner.

The version number of Visual Basic went straight from 12 to 14, skipping 13. This was done to keep VB in line with the version numbering of Visual Studio itself.

#Region directive improvements

#Region directive can now be placed inside methods and can even span over methods, classes and modules.

#Region "A Region Spanning A Class and Ending Inside Of A Method In A Module"
   Public Class FakeClass
    'Nothing to see here, just a fake class.
   End Class

   Module Extensions

    ''' <summary>
    ''' Checks the path of files or directories and returns [TRUE] if it exists.
    ''' </summary>
    ''' <param name="Path">[Sting] Path of file or directory to check.</param>
    ''' <returns>[Boolean]</returns>
    <Extension>
    Public Function PathExists(ByVal Path As String) As Boolean
        If My.Computer.FileSystem.FileExists(Path) Then Return True
        If My.Computer.FileSystem.DirectoryExists(Path) Then Return True
        Return False
    End Function

    ''' <summary>
    ''' Returns the version number from the specified assembly using the assembly's strong name.
    ''' </summary>
    ''' <param name="Assy">[Assembly] Assembly to get the version info from.</param>
    ''' <returns>[String]</returns>
    <Extension>
    Friend Function GetVersionFromAssembly(ByVal Assy As Assembly) As String
#End Region
        Return Split(Split(Assy.FullName, ",")(1), "=")(1)
    End Function
End Module

Comments after implicit line continuation

VB 14.0 introduces the ability to add comments after implicit line continuation.

Dim number =
    From c As Char 'Comment
    In "dj58kwd92n4" 'Comment
    Where Char.IsNumber(c) 'Comment
    Select c 'Comment

Exception handling

During coding, unexpected errors do arise frequently enough, which requires debugging and testing. But sometimes the errors are indeed expected and to bypass it, there is the Try..Catch..Throw..Finally..End Try block.

To manage an error correctly, the code is put into a Try..Catch block, whereby the Catch, as the name states, will catch all the exceptions that arise in this block.

And in case of exception, we have the possibility to Throw the error, that is return it to notify the user or manage it internally in the code itself.

The Finally part is the final code that, whatever the outcome be, if there is an exception or not, the code will run before going out of the block.

In case we need to pop-out of the clock, there is the Exit Try statement that can be used. But here also, the code in the Finally section will be executed before ending.

The syntax is simple;

Try
    [ tryStatements ]
    [ Exit Try ]
[ Catch [ exception [ As type ] ] [ When expression ]
    [ catchStatements ]
    [ Exit Try ] ]
[ Catch ... ]
[ Finally
    [ finallyStatements ] ]
End Try

where only the Try and End Try is compulsory. The rest can be ignored but as a good practice, do include the Finally part, even if it would be left blank.

Coming to the exception, there are different type of exception that can be caught. They are ready made exceptions available from the .Net Framework, as below;

Exception ClassBrief Description
System.IO.IOExceptionHandles I/O errors
System.IndexOutOfRangeExceptionRefers to an array index out of range
System.ArrayTypeMismatchExceptionWhen type is mismatched with the array type
System.NullReferenceExceptionHandles errors generated from referencing a null object.
System.DivideByZeroExceptionHandles errors generated from dividing a dividend with zero.
System.InvalidCastExceptionHandles errors generated during typecasting.
System.OutOfMemoryExceptionHandles errors generated from insufficient free memory.
System.StackOverflowExceptionHandles errors generated from stack overflow.
---------------------------------------------------

Multiline string literals

VB now allows string literals that split over multiple lines.

Old syntax:

Dim text As String = "Line1" & Environment.NewLine & "Line2"

New syntax:

Dim text As String = "Line 1
Line 2"

NameOf operator

The NameOf operator resolves namespaces, types, variables and member names at compile time and replaces them with the string equivalent.

One of the use cases:

Sub MySub(variable As String)
    If variable Is Nothing Then Throw New ArgumentNullException("variable")
End Sub

The old syntax will expose the risk of renaming the variable and leaving the hard-coded string to the wrong value.

Sub MySub(variable As String)
    If variable Is Nothing Then Throw New ArgumentNullException(NameOf(variable))
End Sub

With NameOf, renaming the variable only will raise a compiler error. This will also allow the renaming tool to rename both with a single effort.

The NameOf operator only uses the last component of the reference in the brackets. This is important when handling something like namespaces in the NameOf operator.

Imports System

Module Module1
    Sub WriteIO()
        Console.WriteLine(NameOf(IO)) 'displays "IO"
        Console.WriteLine(NameOf(System.IO)) 'displays "IO"
    End Sub
End Module

The operator also uses the name of the reference that is typed in without resolving any name changing imports. For example:

Imports OldList = System.Collections.ArrayList

Module Module1
    Sub WriteList()
        Console.WriteLine(NameOf(OldList)) 'displays "OldList"
        Console.WriteLine(NameOf(System.Collections.ArrayList)) 'displays "ArrayList"
    End Sub
End Module

Null conditional operator

To avoid verbose null checking, the ?. operator has been introduced in the language.

The old verbose syntax:

If myObject IsNot Nothing AndAlso myObject.Value >= 10 Then

Can be now replaced by the concise:

If myObject?.Value >= 10 Then

The ? operator is particularly powerful when you have a chain of properties. Consider the following:

Dim fooInstance As Foo = Nothing
Dim s As String

Normally you would have to write something like this:

If fooInstance IsNot Nothing AndAlso fooInstance.BarInstance IsNot Nothing Then
    s = fooInstance.BarInstance.Baz
Else
    s = Nothing
End If

But with the ? operator this can be replaced with just:

s = fooInstance?.BarInstance?.Baz

Partial Modules and Interfaces

Similar to partial classes the new version of Visual Basic is now able to handle partial modules and partial interfaces. The syntax and behaviour is exactly the same as it would be for partial classes.

A partial module example:

Partial Module Module1
  Sub Main()
    Console.Write("Ping -> ")
    TestFunktion()
  End Sub
End Module

Partial Module Module1
  Private Sub TestFunktion()
    Console.WriteLine("Pong")
  End Sub
End Module

And a partial interface:

Partial Interface Interface1
  Sub Methode1()
End Interface

Partial Interface Interface1
  Sub Methode2()
End Interface

Public Class Class1
  Implements Interface1
  Public Sub Methode1() Implements Interface1.Methode1
    Throw New NotImplementedException()
  End Sub

  Public Sub Methode2() Implements Interface1.Methode2
    Throw New NotImplementedException()
  End Sub
End Class

Just like for partial classes the definitions for the partial modules and interfaces have to be located in the same namespace and the same assembly. This is because the partial parts of the modules and interfaces are merged during the compilation and the compiled assembly does not contain any indication that the original definition of the module or interface was split.

Read-Only Auto-Properties

Read-only properties were always possible in VB.NET in this format:

Public Class Foo

  Private _MyProperty As String = "Bar"

  Public ReadOnly Property MyProperty As String
    Get
      Return _MyProperty
    End Get
  End Property

End Class

The new version of Visual Basic allows a short hand for the property declaration like so:

Public Class Foo

  Public ReadOnly Property MyProperty As String = "Bar"

End Class

The actual implementation that is generated by the compiler is exactly the same for both examples. The new method to write it is just a short hand. The compiler will still generate a private field with the format: _<PropertyName> to back the read-only property.

String interpolation

This new feature makes the string concatenation more readable. This syntax will be compiled to its equivalent String.Format call.

Without string interpolation:

String.Format("Hello, {0}", name)

With string interpolation:

$"Hello, {name}"

The two lines are equivalent and both get compiled to a call to String.Format.

As in String.Format, the brackets can contain any single expression (call to a method, property, a null coalescing operator et cetera).

String Interpolation is the preferred method over String.Format because it prevents some runtime errors from occurring. Consider the following String.Format line:

String.Format("The number of people is {0}/{1}", numPeople)

This will compile, but will cause a runtime error as the compiler does not check that the number of arguments match the placeholders.