1.2 Syntax Differences

Syntax differences are the most common differences that we think about when comparing two languages. Syntax differences refer to differences in the keywords and format of statements used to perform identical tasks. For instance, in C#, a language statement is terminated with a semicolon; in VB, a language statement is terminated with the carriage return/linefeed character sequence. In this section, we'll survey the syntactical differences between VB.NET and C#.

1.2.1 Case Sensitivity

One major difference between the languages is that C# is case sensitive, while VB.NET is not. That means that while it is okay in VB.NET to write:

system.console.writeline("hello world") 

(all in lowercase), in C# that line results in an error. The correct way to invoke this command in C# is:

System.Console.WriteLine("hello world"); 

Both C# and VB.NET compile to a language known as Intermediate Language (IL). Interestingly, IL is case sensitive, which means that VB must convert lines at compile time to match the correct casing of the original command at the IL level.

A side effect of not being case sensitive is that at times, the compiler may not match casing correctly to the original declaration of a function, resulting in incorrect behavior. For example:

figs/vbicon.gif
 
Class Account
   Overloads Function toString( _
      ByVal Format As String) As String
      Return "My String with Format"
   End Function
  
   Overloads Overrides Function toString(  ) As String
      Return "My String"
   End Function
End Class
  
Module App
   Sub Main(  )
      Dim acct As Object = New Account(  )
      System.Console.WriteLine(acct.ToString(  ))
   End Sub
End Module

This code has strange results in VB.NET. The VB compiler cases the toString method incorrectly to match the first definition of toString in the Account class (with lowercase T), rather than matching both definitions to the one inherited from System.Object (with capital T). The end result is that toString does not override the ToString method in the base class, and the toString method is never called. This example shows the complexity of having a case-insensitive language in a case-sensitive world.

What happens if you add two public functions in C# with the same name but cased differently? VB cannot use the function, and complains that it cannot resolve the function. For example, a Banking class written in C# has a MakeDeposit and a makedeposit method. You can reference the DLL in VB, and you can create an instance of the Banking class, but if you try to use either MakeDeposit or makedeposit, the compiler complains that it cannot figure out which one to use. To prevent this, you could ask the compiler to test for Common Language Specification (CLS) compliance. The CLS describes what is legal to make public in order to be compatible with other languages. To tell the compiler to check for CLS compliance, add the following line of code to the AssemblyInfo.cs file in your C# project:

[assembly: System.CLSCompliant(true)]

If you're using the C# command-line compiler, simply add the line to your source code file after any using statements. After adding that line, the C# compiler gives you an error if two public functions in your class differ only by case.

1.2.2 Line Termination

C# statements can be split into multiple lines with CRLF and are terminated with a semicolon. VB.NET lines can only be broken with a continuation character and are terminated with CRLF. The following code illustrates breaking up lines in C#:

figs/csharpicon.gif
 
//one line of code in C#
string sName = sFirstName +
               sLastName;   
//semicolon signals the end of a statement

The semicolon indicates the end of a code statement. You can break up the line in almost any place. You can go as far as putting each word on a separate line and even adding comments to the end of each segment. For example:

figs/csharpicon.gif
 
string
sName //variable
=  //operator
sFirstName //first name
+ //plus operator
sLastName; 
//semicolon signals the end of a statement

You can do the same with string literals if you precede the string with the @ symbol:

figs/csharpicon.gif
 
string
sName = @"John Jacob Jingle 
Hymer Smith";

However, be aware that code like that above results in a string with a carriage return embedded.

In VB, to break a line into segments, you must add a space and the underscore character. For example:

figs/vbicon.gif
 
'one line in VB
Dim sName As String = sFirstName + _
        sLastName

As in C#, you can break up every word if you like, as in the example below. (However, unlike C#, in VB it is illegal to put comments after each segment.)

figs/vbicon.gif
 
'one line in VB
Dim _
sName _
As _
String _
= _
sFirstName _
+ _
sLastName

Unlike C#, it is illegal to break up string literals into two separate lines.

1.2.3 Comments

C# distinguishes between single line comments and block comments. Single line comments use a double slash, as follows:

figs/csharpicon.gif
 
//This is a comment
void MakeDeposit(int Amount)
{
    int _Balance; //stores the Account balance

Notice that there is a comment above the function declaration and a comment after the declaration of the _Balance field. When you use the double slash, all text after the slashes is assumed to be part of the comment. A block comment uses a slash followed by an asterisk (/*) at the beginning of the block, and an asterisk followed by a slash at the end of the comment block (*/). Here's an example:

figs/csharpicon.gif
 
 /* 
Function: MakeDeposit
Scope: Public
Description: Increases the balance for the account.
Author: Jose Mojica
*/
public void MakeDeposit(int Amount /*Deposit Amount*/, int 
AmountAvail /*how much is available*/)
{
}

Block comments enable you to write full paragraphs of comments without having to put double slashes on every line, but they also allow you to insert a comment within a single line of code. Block comments can have comments embedded within them, as in the following:

figs/csharpicon.gif
 
/*
//this is an embedded comment
*/

VB.NET has only a single-line comment. Comments are made either with the Rem statement or with a single apostrophe (the preferred method). Here are some examples:

figs/vbicon.gif
 
'This is a comment
Rem This is another comment
Sub MakeDeposit(ByVal Amount As Integer)
   Dim _Balance As Integer 'Account balance
End Sub

One limitation with comments in VB is that you cannot insert a comment in the middle of a line of code, as you can with block comments in C#.

1.2.4 Namespace Declaration and Usage

A namespace is a group of classes that have the same name prefix. For example, if the WidgetsUSA namespace has classes named Checking and Savings, the full name for these classes is WidgetsUSA.Checking and WidgetsUSA.Savings. The namespace declaration prefixes each class name within it.

Both VB.NET and C# enable you to define a namespace. Here are some code examples:

figs/csharpicon.gif
 
namespace WidgetsUSA
{
   namespace Banking
   {
      public class Checking
      {
      }
      public class Savings
      {
      }
   }
}

The same code can be written in VB as follows:

figs/vbicon.gif
 
Namespace WidgetsUSA
   Namespace Banking
       Class Checking
       End Class
       Class Savings
       End Class
   End Namespace
End Namespace

The full names for the classes in these examples are WidgetsUSA.Banking.Checking and WidgetsUSA.Banking.Savings. The namespace declarations attempt to make the class names unique for a particular company. However, it gets cumbersome to type long class names in declarations. Therefore, each language provides a statement that allows you to omit the namespace name and use the short class name in declarations instead. In C#, this is done with the using statement:

figs/csharpicon.gif
 
using WidgetsUSA.Banking;
class App
{
   static void Main(  )
   {
      Checking check = new Checking(  );
   }
}

The equivalent of using in VB is Imports:

figs/vbicon.gif
 
Imports WidgetsUSA.Banking
Class App
   Shared Sub Main(  )
      Dim check As Checking = New Checking(  )
   End Sub
End Class

In both C# and VB.NET, you can assign a prefix to a namespace. This helps solve problems of ambiguity in which multiple namespaces have the same class name. Consider two classes: MyCompany.SharedCode.DatabaseClasses.Connection and SomeOtherCompany.Modem.Connection. Suppose a developer writes code to use or import the namespace for each class as follows:

figs/vbicon.gif
 
Imports MyCompany.SharedCode.DatabaseClasses
Imports SomeOtherCompany.Modem
  
Class App
   Shared Sub Main(  )
      Dim cn As Connection
   End Sub
End Class

The compiler complains that Connection in these declarations is ambiguous; it could be from either namespace. One solution is to assign a prefix to one or both of the namespaces as follows:

figs/csharpicon.gif
 
using db=MyCompany.SharedCode.DatabaseClasses;
using SomeOtherCompany.Modem;
  
class App
{
    static void Main(  )
    {
        db.Connection cn;
    }
}

Here is the equivalent code in VB.NET:

figs/vbicon.gif
 
Imports db=MyCompany.SharedCode.DatabaseClasses
Imports SomeOtherCompany.Modem
  
Class App
   Shared Sub Main(  )
      Dim cn As db.Connection
   End Sub
End Class

The first using statement in C# and the first Imports statement in VB assign a prefix (db) to the MyCompany.SharedCode.DatabaseClasses namespace. You can then use db in your code instead of the namespace name. This is easier to type and also solves ambiguity problems. Of course, you could just use the fully qualified namespace name whenever you refer to the class to solve ambiguity problems.

VB has one enhancement that C# lacks. It lets you use Imports not only with a namespace name (as does C#), but also with a class name. For example:

figs/vbicon.gif
 
Imports Microsoft.VisualBasic.ControlChars
  
Module App
   Sub Main(  )
      Dim s As String = "Hello" + NewLine + "World"
      System.Console.WriteLine(s)
   End Sub
End Module

The Imports statement references a namespace (Microsoft.VisualBasic) and a class (ControlChars). Therefore the code in Main can use the constants in the class without having to use the class' complete name. One of these constants is NewLine, which represents a carriage return and a line feed character.

1.2.5 Variable Declaration

In C#, the variable type always precedes the variable name. Here are some examples:

figs/csharpicon.gif
 
int x;
decimal y;
rectangle z;
object obj;

In VB, the variable name always is first, then the variable type. VB also requires a Dim or an access modifier (Public, Private, Friend, Protected, or Protected Friend). A declaration that uses Dim is Private by default. The following VB code is equivalent to the previous C# code:

figs/vbicon.gif
 
Dim x As Integer
Dim y As Decimal
Dim z As Rectangle
Dim obj As Object

Both languages enable you to create an instance of a class using the new keyword. Here are some examples in C#:

figs/csharpicon.gif
 
class Account
{
}
  
class App
{
   static void Main(  )
   {
      //example 1
      Account acct = new Account(  );
  
      //example 2
      Account acct2;
      acct2 = new Account(  );
   }
}

You can combine the object declaration and instantiation onto one line, or you can separate the instantiation from the declaration.

VB has three ways of using the new operator, as illustrated below:

figs/vbicon.gif
 
Class Account
End Class
  
Class App
   Shared Sub Main(  )
      'example 1
      Dim acct As Account = new Account(  )
  
      'example 2
      Dim acct2 As Account
      acct2 = new Account(  )
  
      'example 3
      Dim acct3 As New Account
   End Sub
End Class

All three examples generate the same IL. Example 3 is similar to example 1—it Dims a variable of type Account and creates an object of type Account. Unlike previous versions of VB, example 3 creates an instance of the Account object immediately. In VB 6 and before, when you used the As New notation, the object would not be instantiated until you used it.

1.2.6 Variable Initialization

C# requires you to initialize local variables explicitly. Consider the following declaration:

figs/csharpicon.gif
 
class Account
{
   int Balance;        //instance field
  
   public void MakeDeposit(  )
   {
      int tempBalance;    //local variable
      //compiler error
      Console.WriteLine(tempBalance);
   }
}

The Account class has a field, Balance, a method, MakeDeposit, and a local variable, tempBalance. In C#, you do not have to initialize fields before using them. Fields are auto-initialized to 0 if they are numeric or to null if they are reference types. However, the C# compiler issues an error if you attempt to use a local variable before assigning it a value.

This is not the case in VB. VB.NET automatically initializes all local variables to 0 or to Nothing (or the equivalent, depending on the class). Consider the following VB code:

figs/vbicon.gif
 
Class Account
    Dim Balance As Integer
  
    Sub MakeDeposit(  )
        Dim tempBalance As Integer
        'no compiler error
        System.Console.WriteLine(tempBalance)
    End Sub
End Class

In this example, both Balance and tempBalance are initialized to 0.

Inside the IL

When both compilers generate the IL for the local variables in a procedure, they add the init keyword to the variable declarations section, which tells the JIT compiler to initialize local variables to 0 or null. This IL code shows the use of the init keyword:

.locals init ([0] int32 tempBalance)

The C# compiler enforces the rule that local variables be initialized at compile time.

1.2.7 Declaring Function Parameters

There are three kinds of parameter direction: in (or by value), in,out (or by reference), and out. When an argument is passed by value, changes made in the called function are not reflected back to the caller; when an argument is passed by reference, they are reflected. With reference parameters, memory is allocated by the caller but the function can change the value. With out parameters, the memory is allocated and the value set by the function, with the caller receiving only the value. Both C# and VB can use all three forms of parameters; however, they work a little differently between the languages. Consider the following two examples in C#:

figs/csharpicon.gif
 
void MakeDeposit(int x, ref int y, out int z)
{
   x = 10; //changes not reflected to caller
   y = 10; //changes reflected to caller
   z = 10; //required. Changes expected and 
           //reflected to the caller.
}
  
void MakeDeposit(object obj1, ref object obj2, 
                 out object obj3)
{
   obj1 = new object(  ); //changes not reflected 
                        //to caller. 
   obj2 = new object(  ); //changes reflected to 
                        //caller, which now has a 
                        //reference to a different      
                        //object than the 
                        //original one
   obj3 = new object(  ); //required. Function 
                        // must allocate
                        //the object.
}

The first example accepts value types, and the second example accepts reference types. Both versions are shown to illustrate what it means to send an object by reference. Sometimes, developers incorrectly assume that if you pass in an object by value to a function, the function cannot change the fields of that object. That is not the case; consider the following code:

figs/csharpicon.gif
 
class person
{
    public int Age;
}
  
class App
{
    static void ChangeAge(person p1)
    {
        p1.Age=10;
    }
}

In this example, p1 is a by value parameter, yet if the function changes the Age field, the caller will see that the Age field was in fact changed. "By value" applies only to the object the variable points to; the object's fields can always be changed no matter how the parameter direction was declared. In the case of objects, sending an object by value only means that if the function sets the variable to a different object, the caller will still hold a reference to the original object when the function ends. If an object is sent by reference, and the function sets the variable representing the object to a new object, then the caller will hold a reference to the new object when the function returns.

Out parameters are really reference parameters marked with a special attribute to simplify how parameters are passed when remoting. When the caller and the object live in different machines, the less data that is transmitted in each call across the network, the better. Parameters sent by value only need to be transmitted from the caller to the object and not back. Parameters sent by reference need to be sent twice: from the caller to the object, and then back to the caller. Out parameters only need to be transmitted from the object to the caller.

VB supports all three versions of parameter passing. By value parameters are specified either by omitting a direction keyword as in C# or by using the ByVal keyword:

figs/vbicon.gif
 
Sub MakeDeposit(ByVal num1 As Integer)
End Sub
  
Sub MakeDeposit(num1 As Integer)
End Sub

The num1 parameter is accepted by value in both routines. You must use the ByRef keyword to pass a parameter by reference, as in the following example:

figs/vbicon.gif
 
Sub MakeDeposit(ByRef num2 As Integer)
End Sub

VB does not have a keyword for out parameters; however, you can apply the <Out> attribute to represent out parameters. For example:

figs/vbicon.gif
 
Imports System.Runtime.InteropServices
Sub MakeDeposit(<Out(  )> ByRef num1 As Integer)
End Sub

This code declares the num1 parameter in MakeDeposit as an out parameter. The C# version is simpler, since the language provides a keyword that automatically adds the attribute. However, placing the attribute in VB accomplishes the same task. A drawback of the VB style is that the language does not enforce the concept automatically. In C#, if you mark a parameter as out, the function must set the parameter to a value before returning to the caller; otherwise, the compiler generates an error. But in VB, you can apply the attribute to a ByRef parameter or to a ByVal parameter. The latter is a mistake, but the compiler does not enforce the rule.

1.2.8 Passing Function Parameters

In C#, if a function contains ref parameters, you must use the ref keyword in front of each by reference argument when you call it. The same is true for out parameters—the out keyword must appear before any argument that corresponds to an out parameter. Also in C#, it is illegal to pass in a literal value as an argument for a ref or out parameter. (You cannot pass a number for a ref int parameter, for example.) Any variable you pass as a ref argument must be initialized before making the method call. The following code segment illustrates these principles:

figs/csharpicon.gif
 
static void DoSomething(int x, ref int y, 
                        out int z)
{
   z=45;
}
  
static void Main(string[] args)
{
   int y=4; //you must declare a variable 
            //and initialize it.
   int z;
   //notice the use of the ref and out
   //before each ref and out argument.
   DoSomething(5,ref y,out z);
}

In VB, you do not use any keywords in front of the method arguments, whether they are ByVal, ByRef, or <Out> ByRef. The example below shows how to call functions with ByRef parameters in VB.NET:

figs/vbicon.gif
 
Imports System.Runtime.InteropServices
  
Module Module1
   Sub DoSomething(ByVal x, ByRef y, <Out(  )> ByRef z)
      z = 45
   End Sub
  
   Sub Main(  )
      Dim y As Integer
      Dim z As Integer
  
      'y and z do not have to be
      'initialized because VB auto
      'initializes variables
      DoSomething(5, y, z)
      'it is also legal in VB.NET to
      'pass literal values for ByRef
      DoSomething(5, 10, 20)
   End Sub
End Module

Notice that it is not necessary to use ByRef in front of the ByRef arguments or to initialize argument variables, because VB auto-initializes local variables. Notice too that VB lets you send literal values for ByRef parameters.

Inside the IL

Whenever you make a method call in VB.NET and you use a literal value for a ByRef parameter, at the IL level VB declares a hidden local variable, assigns it the value you are passing, and passes the address of the variable instead of the literal value to the function.

1.2.9 Optional Parameters

In VB, you specify optional parameters as follows:

figs/vbicon.gif
 
Sub MakeDeposit(Optional ByVal x As Integer=10)
End Sub

Optional means the parameter may be omitted. In other words, you can call MakeDeposit(20) or MakeDeposit( ). If the parameter is omitted, the default value (10 in the declaration for MakeDeposit above) is used. Default values must be constants because if the caller omits the value, the compiler writes a call that uses the default value. Thus, at runtime it appears as though the caller did not omit the value. The ability to omit parameters in the call is specific to the VB compiler. For example, if you write a class in VB with a method that has an optional parameter, and then write code to use the class in C#, your C# code cannot omit the parameter in the call.

You can define a parameter as optional in C# as well using an attribute. However, in C# the parameter will not be optional. If the C# class is used with a VB program, the VB code can omit the optional parameter. In this case, its value will be 0 or nothing, depending on the variable type, since there is no way to specify the default value through attributes in C#. The following code shows how to define a method with an optional parameter in C#:

figs/csharpicon.gif
 
using System.Runtime.InteropServices;
public void MakeDeposit([Optional] int Amount)
{
}

1.2.10 Parameter Lists

In C# and VB, you can declare a single parameter as a parameter list (or parameter array)—a parameter that can accept a variable number of arguments, all of the same type, or an array with a variable number of elements. The following code example shows how to define a parameter list array in C# and how to invoke the method that contains it:

figs/csharpicon.gif
 
//definition (meant to be in a class)
public void MakeDeposit(params int[] 
                        Amount) { }
//calling the method
//(code meant to be in a function)
Account acct = new Account(  );
//a call with multiple arguments
acct.MakeDeposit(50,100,20,30);
//a call with no arguments
acct.MakeDeposit(  );
//a call with an array argument
int[] Amounts = {50,100,20,30};
acct.MakeDeposit(Amounts);

The code invokes the MakeDeposit method three times: once with four parameters, once with none, and once with an array. To the .NET runtime, the MakeDeposit call simply accepts an array of integers. If you pass multiple arguments, the compiler generates code to create the array and fill it with the values of the call, then calls MakeDeposit passing this array of values.

The following is the VB equivalent:

figs/vbicon.gif
 
'definition (meant to be in a class)
Sub MakeDeposit(ParamArray Amount As Integer(  ))
End Sub
  
'calling the method (meant to be in a function)
Dim acct As New Account
' a call with multiple parameters
acct.MakeDeposit(50,100,20,30)
'a call with no parameters
acct.MakeDeposit(  )
'here is a call with an array, also acceptable
Dim amts As Integer(  ) = { 100, 200, 30, 50 }
acct.MakeDeposit(amts)

1.2.11 Method Declaration

In C#, all methods are functions. Some functions return nothing (void), as in the following:

figs/csharpicon.gif
 
public void MakeDeposit(int Amount)
{
}

VB distinguishes between two types of methods: Subs and Functions. A Sub is a method that does not return a value. When a VB program is compiled, subroutines are turned into functions that return void, just like in C#. The following code shows a VB.NET subroutine and a VB.NET function:

figs/vbicon.gif
 
Sub MakeDeposit(ByVal Amount As Integer)
End Sub
  
Function IsOpen(ByVal AcctID As Integer) As Boolean
End Function

Notice that in a function you add As after the parameter list, followed by the return type.

1.2.12 Returning Output Parameters

Both C# and VB.NET have a return keyword to return the value of a function and exit the function at the same time. The following illustrates its use:

figs/csharpicon.gif
 
public class Person
{
    int m_Age = 10;
    //use of return with a parameter
   
    public int GetAge(  )
    {
       return m_Age;
    }
  
    public void Speak(  )
    {
        if (m_Age < 1)
            return;
        //do something else here
    }
}

The GetAge function returns the contents of the m_Age field; the Speak function returns nothing.

VB has another way to return parameters for compatibility with older versions of VB. You simply set the function name equal to the return value. (Note that doing so does not exit the function automatically.)

Inside the IL

The trick of setting the function name to the output parameter in VB is accomplished at the IL level by declaring a hidden variable with the same name as the name of the function. Because of this, there is a distinction between GetName (the variable) and GetName() (the function). For example:

Function GetAge() As Integer
    GetAge = 100
    Return GetAge
End Function
 
Function GetAge() As Integer
    GetAge = 100
    Return GetAge()
End Function

The first version returns 100 to the caller. In the second version, Return GetAge() cause the code to call GetAge infinitely.

figs/vbicon.gif
 
Public Class Person
   Dim m_Age As Integer = 10
  
   'use of return with a parameter
   Function GetAge(  ) As Integer
      Return m_Age
   End Function
  
   Sub Speak(  )
      If m_Age < 1 Then Return
      'do something else here
   End Sub
  
   'You can also use the function name
   'to return a value
   Function GetName(  ) As String
      GetName = "Smith"
   End Function
End Class

1.2.13 Program Startup

All EXE programs begin with a Main procedure. VB has a feature that also enables a WinForms project to specify a startup form instead of a Main procedure. However, even in this case, programs begin with a Main procedure. (Take a look at Section 1.4.3 to see how this works.)

In C#, Main (with a capital M) is a static procedure in a class. In VB.NET, Main is a shared procedure in a class. In VB.NET, Main can also be inside a Module. (A module is a class in which all methods are automatically Shared. See Section 1.2.17 for details.)

Both C# and VB enable you to write a Main procedure in three different ways. In its simplest form, you can write a Main procedure that has no parameters. Here is an example:

figs/csharpicon.gif
 
class App
{
    static void Main(  )
    {
    }
}
figs/vbicon.gif
 
Class App
   Shared Sub Main(  )
   End Sub
End Class

(Shared in VB.NET is the same as static in C#.) You could also write a Main procedure with an incoming parameter of type string array. This string array contains the command-line arguments used when running the program. For example, a user may run your program as follows:

program.exe param1 param2 /param3 "param4 param5" 

Here is an example of using that form of Main:

figs/csharpicon.gif
 
class App
{
   static void Main(string[] args)
   {
      foreach(string arg in args)
      {
         System.Console.WriteLine(arg);
      }
   }
}
figs/vbicon.gif
 
Class App
   Shared Sub Main(ByVal args As String(  ))
      Dim arg As String
      For Each arg In args
         System.Console.WriteLine(arg)
      Next
   End Sub
End Class

In this version of Main, args is a string array containing the program's command-line arguments. The command-line arguments do not include the program name; they are the strings that come after the program name. Each argument is separated by a space. To have a string containing a space as a single parameter, you must add quotation marks around it. The code outputs all command-line arguments to the console window. Assuming we were using the command line described earlier, the output is:

param1
param2
/param3
param4 param5

You can write a third version of Main as a function that returns an integer. This version can take either the string array as a parameter or no parameters. The integer is programmer-defined, which means that you must define meaningful values. Normally, 0 denotes success, and non-zero values denote error conditions. Here is an example:

figs/csharpicon.gif
 
class App
{
    static int Main(  )
    {
        return 0;
    }
}
figs/vbicon.gif
 
Class App
   Shared Function Main(  ) As Integer
       Return 0
   End Function
End Class

For backward compatibility, VB also has a Command function that enables you to retrieve the command-line arguments as a single string. Here is an example:

figs/vbicon.gif
 
Imports Microsoft.VisualBasic
 
Class App
   Shared Sub Main(  )
      Dim args As String = Command(  )
      System.Console.WriteLine(args)
   End Sub
End Class

1.2.14 Exiting Programs/Methods/Loops

VB.NET offers a variety of statements to exit a program, method, or loop. To exit a program, you use the End statement. Placing End anywhere in the code results in the program terminating. For example:

figs/vbicon.gif
 
Module App
   Sub CheckSecurity(ByVal sID As String)
      If sID = "" Then
         End
      End If
   End Sub
   Sub Main(  )
      CheckSecurity("")
   End Sub
End Module

C# does not have an equivalent method to exit the program. However, both VB and C# can make use of the System.Environment.Exit method. Here is a C# example using the Exit method:

figs/csharpicon.gif
 
class App
{
   static void CheckSecurity(string sID)
   {
      if (sID == "") System.Environment.Exit(1);
   }
  
   static void Main(string[] Args)
   {
      CheckSecurity("");
   }
}

Exit accepts one parameter, the exit code.

VB has several statements for exiting methods, including Exit Sub, Exit Function, and Exit Property. An example with Exit Function is:

figs/vbicon.gif
 
Function MakeDeposit(ByVal Amount As Integer) As Integer
    If Amount < 0 Then
        Exit Function
    End If
    m_Balance += Amount
    Return m_Balance
End Function

C# does not have an equivalent method. However, the same task can be accomplished with the return statement. In fact, that's all that VB does internally.

VB.NET also has methods for exiting loops, including Exit Do (for Do-While loops) and Exit For (for For-Next loops). For example:

figs/vbicon.gif
 
Class People
   Dim Total As Integer
   Sub FillAuditorium(  )
      Dim iCount As Integer
      For iCount = 1 To 500
         Total += iCount
         If Total > 250 Then
            Exit For
         End If      
      Next
      System.Console.WriteLine(iCount)
   End Sub
End Class

C# has an equivalent statement, break. The break statement works with for loops, while loops, and switch statements. The following C# code illustrates the use of break to exit a method prematurely:

figs/csharpicon.gif
 
class People
{
   int Total;
  
   public void FillAuditorium(  )
   {
      int iCount;
      for (iCount = 1; iCount <= 500; iCount++)
      {
         Total += iCount;
         if (Total > 250)
            break;
      }
      System.Console.WriteLine(iCount);
   }
}

One C# feature not available in VB.NET is the continue statement. The continue statement enables you to advance the loop. The following code demonstrates the use of continue:

figs/csharpicon.gif
 
public class Person
{
   string LastName;
   int Age;
  
   public static void SearchPeople(Person[] arr, int Age)
   {
      for (int i=0; i < arr.Length; i++)
      {
         if (arr[i].Age != Age)
            continue;
         System.Console.WriteLine(arr[i].LastName);
      }
   }
}

In this code, the loop in the SearchPeople function iterates an array of Persons looking for any person that matches a specific age. An if statement compares a Person's age to the desired age. If they are not equal, the code calls continue, which advances the loop and returns to the first line of code in the loop.

1.2.15 Member Scope

When declaring class members such as fields, methods, properties, events, nested classes, etc., C# makes members private by default, while VB makes members (other than fields declared with Dim) public by default.

The following table shows the keywords used in each language to denote the scope of a class member:

C#

VB.NET

Comments

public

Public

Default in VB

private

Private

Default in C#

internal

Friend

 

protected

Protected

 

protected internal

Protected Friend

 

Outer classes at the IL level have only two possible scopes: private or public. Private means that the class is available at the assembly level (in most cases this means the project level), and public means that it is visible outside of the assembly. VB.NET uses the Friend keyword to denote assembly scope for an outer class. C# uses the internal keyword to denote assembly scope.

1.2.16 Static and Shared Methods

Static methods are methods that are not attached to a particular instance of a class. In other words, you may invoke a static method without creating an instance of the class. Along the same lines, a static field is a field that is not dependent on the instance of the class. Static fields are allocated when the type (the class in which they are declared) is allocated. Type allocation occurs just before any code that refers to the class executes. Static fields are allocated for the duration of the program.

The limitation of static methods is that they can only invoke other static methods, and they can only use static fields. They cannot call instance methods or use instance fields without first creating an instance of the class. The following code illustrates static methods and fields:

figs/csharpicon.gif
 
class Account
{
   public static int TotalAccounts;
   int m_ID;
  
   public static int GetNextAccountID(  )
   {
      return TotalAccounts;
   }
  
   public Account(  )
   {
      m_ID = GetNextAccountID(  );
      TotalAccounts++;
   }
}

The Account class contains two fields. One, TotalAccounts, is marked as static. (All fields and functions have been marked as public only for convenience; static fields do not need to be public.) The other, m_ID, is an instance field.

This code also defines a static method called GetNextAccountID. If you study the code, you'll notice that instance functions (such as the class' constructors) can call static functions. Instance functions can also access static fields. It is not legal, however, for a static function to call instance functions or to use instance fields. If a static function needs to call an instance method, it must first create an instance of the type and then call the instance method.

To use static members outside of the class in which they are defined in C#, you must use the class' name. For example, if you would like to access the GetNextAccountID function or the TotalAccounts field, you must do it as follows:

figs/csharpicon.gif
 
class App
{
    static void Main(string[] args)
    {
        int ID = Account.GetNextAccountID();
    }
}

It is illegal in C# to invoke a static method or use a static field through an instance variable. For example, the following code results in a compiler error:

figs/csharpicon.gif
 
class App
{
    static void Main(string[] args)
    {
        Account acct = new Account(  );
        //illegal in C#
        int ID = acct.GetNextAccountID(  );  //error
    }
}

VB also supports static fields and static functions. VB uses the Shared keyword to denote static members. The limitations for shared methods in VB are identical to those in C#. The following code shows the VB equivalent of the previous C# code:

figs/vbicon.gif
 
Class Account
    Shared TotalAccounts As Integer
    Dim m_ID As Integer
  
    Shared Function GetNextAccountID(  ) As Integer
        return TotalAccounts
    End Function
  
    Sub New(  )
        m_ID = GetNextAccountID(  )
        TotalAccounts+=1
    End Sub
End Class

As in C#, VB shared functions can only call other shared methods or use shared fields. It is legal, however, for instance functions to use any shared fields or call any shared methods.

VB enables you to call a shared method or to use a shared field using a variable that points to an instance of the class, as in the following example:

figs/vbicon.gif
 
Class App
   Shared Sub Main(  )
      'legal in both languages
      Dim ID As Integer = Account.GetNextAccountID(  ) 
  
      Dim Acct As New Account(  )
     'legal in VB, not in C#
      ID = Acct.GetNextAccountID(  ) 
   End Sub
End Class

As the example shows, it is legal to invoke the GetNextAccountID function using the class name or an instance of the Account class.

1.2.17 Classes Versus Modules

VB.NET supports code modules, which developers use to write libraries of global functions. For example:

figs/vbicon.gif
 
Module App
    Sub Main(  )
    End Sub
End Module

The VB compiler translates a module into a class in which all members are marked as Shared (static in C#). The generated class is sealed (NotInheritable). Since every member in a module is Shared, you cannot add instance constructors to the module, only a shared constructor.

There is no equivalent in C#, but a C# developer can simulate a module by writing a sealed class with all methods and fields marked as static. One advantage of using a module over a class with all members marked as static, however, is that in VB you can refer to a member of the module directly without specifying the module's name. Normally when you declare a shared method in a class by hand, you must use the name of the class plus the method to invoke it, as in the following example:

figs/vbicon.gif
 
Class Math
   Shared Function Add(Num1 As Integer, _
                   Num2 As Integer) As Integer
   End Function
End Class
  
Module App
   Sub Main(  )
      System.Console.WriteLine(Math.Add(3,4))
   End Sub
End Module

To invoke the Add method, you must write Math.Add. In VB, if the method is part of a module, you may omit the module's name:

figs/vbicon.gif
 
Module Math
   Function Add(Num1 As Integer, _
              Num2 As Integer) As Integer
   End Function
End Module
  
Module App
   Sub Main(  )
      System.Console.WriteLine(Add(3,4))
   End Sub
End Module

In this case, you need only call the Add method. This is true as long as the compiler can tell what Add method to invoke. If you have two modules that have the same method with the same signature, you must fully qualify the name by adding the name of the module, just as if you were invoking a Shared method from the class.

If you are writing a class in C# to be used in VB.NET and want to make it look like a module, you can simply mark every member in the class as static, then reference the Microsoft.VisualBasic.DLL assembly and add the StandardModule attribute (from the Microsoft.VisualBasic.CompilerServices namespace) to your class, as follows:

figs/csharpicon.gif
 
[Microsoft.VisualBasic.CompilerServices.StandardModule]
public class Math
{
   public static int Add(int num1, int num2)
   {
      return num1+num2;
   }
}

A VB project can then refer to the Add function directly without the class name.

1.2.18 If Statements

Both languages have conditional if statements. However, the syntax and semantics differ between the languages. In C#, the conditional statement must be enclosed in parentheses, as follows:

figs/csharpicon.gif
 
if (x > 10)
    DoSomething(  );

Notice that if is in lowercase, there are parentheses surrounding the conditional statement, and that unlike in VB, there is no need for Then at the end. This example shows an if statement with only one task to perform. If there are multiple tasks to perform, they are enclosed in curly brackets, as follows:

figs/csharpicon.gif
 
if (x < 10)
{
    DoTask1(  );
    DoTask2(  );
}

If you want to add an else clause, you use the else keyword in lowercase, as in the following example:

figs/csharpicon.gif
 
if (x < 10)
{
   DoTask1(  );
   DoTask2(  );
}
else
{
   DoOtherTask1(  );
   DoOtherTask2(  );
}

If your else statement needs to test for another condition, it is perfectly fine to include another if statement as part of the else clause, as follows:

figs/csharpicon.gif
 
if (x < 10)
{
   DoTask1(  );
   DoTask2(  );
}
else if (x > 10)
{
   DoOtherTask1(  );
   DoOtherTask2(  );
}
else
{
   DoNothing(  );
}

In VB, the syntax is slightly different. VB uses the If and the required Then keywords as follows:

figs/vbicon.gif
 
If x > 10 Then DoSomething(  )

There is no need for parentheses around the conditional statement. As in C#, an If statement may perform only one task, or it can perform multiple tasks, as in the following:

figs/vbicon.gif
 
'when using "End If" the "Then" is optional
'but VS.NET adds it by default
If x < 10
    DoTask1(  )
    DoTask2(  )
End If

Instead of surrounding the task block with brackets, VB uses the End If statement at the end of the block. An else clause can be specified with the Else keyword:

figs/vbicon.gif
 
If x < 10 Then
    DoTask1(  )
    DoTask2(  )
Else
    DoOtherTask1(  )
    DoOtherTask2(  )
End If

In this case, the End If goes after the Else block. If your else must have another If condition, then, unlike C#, you cannot simply write another If in the same line. Instead VB has a special ElseIf keyword that you must use for the second condition, as follows:

figs/vbicon.gif
 
If x < 10 Then
   DoTask1(  )
   DoTask2(  )
ElseIf x > 10 Then
   DoOtherTask1(  )
   DoOtherTask2(  )
Else 
   DoNothing(  )
End If

When combining clauses in an if statement, both languages use different symbols to represent operators. The following table tells you what operators to use in each language:

VB.NET

C#

Operator

And

&&

and

Or

||

or

Not

!

Boolean opposite

=

==

equals

<>

!=

not equal

1.2.19 Short-Circuiting

In addition to syntax differences, if statements in both languages differ in semantics. The main difference is the use of short-circuiting in C# by default. Consider the following example:

figs/csharpicon.gif
 
static bool DoTask1(  )
{
   return true;
}
  
static bool DoTask2(  )
{
   return false;
}
  
static void Main(string[] args)
{
   //it is unnecessary to execute
   //DoTask2 because DoTask1 returns
   //True, which is enough to satisfy
   //the or clause
   if (DoTask1() || DoTask2(  ))
   {
   }
  
   //it is unnecessary to execute
   //DoTask1 because DoTask2 returns 
   //False, which means the clause is
   //False
   if (DoTask2() && DoTask1(  ))
   {
   }
}

In this example, the function DoTask1 always returns true, and the function DoTask2 always returns false. C# uses a technique called short-circuiting, which means that if part of the statement makes the entire statement true or false, there is no need to process the rest of the statement. For example, in an or operation, if at least one of the clauses is true, then the entire statement is true. In the example above, DoTask1 returns true; therefore, there is no need to execute DoTask2. The second half of the code example contains an and operation. In an and operation, all clauses have to be true. If one of the clauses is false, there is no need to evaluate the rest of the statement. In this example, DoTask2 returns false; therefore, there is no need to evaluate DoTask1.

VB does not short-circuit by default. In VB, all parts of the conditional statement are executed unless you use the special keywords AndAlso or OrElse. For example:

figs/vbicon.gif
 
Shared Function DoTask1(  ) As Boolean
   Return True
End Function
  
Shared Function DoTask2(  ) As Boolean
   Return False
End Function
  
Shared Sub Main(  )
   'VB evaluates each portion of the
   'if clause without short-circuiting
   If DoTask1() Or DoTask2(  )
   End If
  
   If DoTask2() And DoTask1(  )
   End If
End Sub

Both the Or clause and the And clause will execute DoTask1 and DoTask2 without short-circuiting. If you would like to short-circuit, you must replace And with the AndAlso keyword and Or with the OrElse keyword, as follows:

figs/vbicon.gif
 
Shared Function DoTask1(  ) As Boolean
   Return True
End Function
  
Shared Function DoTask2(  ) As Boolean
   Return False
End Function
  
Shared Sub Main(  )
   If DoTask1() OrElse DoTask2(  )
   End If
  
   If DoTask2() AndAlso DoTask1(  )
   End If
End Sub

This code uses short-circuiting. In the OrElse statement, only the DoTask1 clause is executed. In the AndAlso statement, only the DoTask2 clause is executed.

Inside the IL

If you use And and Or in VB.NET instead of the short-circuiting equivalents, at the IL level VB executes all the functions involved in the If first, then compares the results. In the case of short-circuiting, VB executes one statement, then checks the result to see if it needs to continue. If it does not, it skips the rest of the statements. Otherwise it executes the second statement and checks again, and so on.

1.2.20 Conditional Statement

Both C# and VB.NET have a conditional statement that enables you to test one clause and return one value if the clause is true and another if the clause is false. In C#, this is done in the following fashion:

figs/csharpicon.gif
 
static void Main(string[] args)
{
   int Balance = 45;
   int Withdrawal = 50;
  
   string msg = (Balance < Withdrawal) ?
     "Insufficient Funds" : "Successful";
     msg = (Balance < Withdrawal) ? DoTask1(  ) : 
     DoTask2(  );
}

This C# code shows two uses of the conditional statement. The format for the conditional is:

true/false_clause)  ? value_for_true : 
                       value_for_false  

Notice from the code example that you can return literal values for the true and false portions, or you can invoke functions that return a value.

VB.NET also has a conditional in the form of the IIf function. For example:

figs/vbicon.gif
 
Sub Main(  )
   Dim Balance As Integer = 45
   Dim Withdrawal As Integer = 50
  
   Dim msg As String = IIf(Balance < Withdrawal, _
                      "Insufficient Funds", _
                      "Successful")
   msg = IIf(Balance < Withdrawal, _
             DoTask1(  ), _
             DoTask2(  ))
   IIf(Balance < Withdrawal, DoTask1(), DoTask2(  ))
End Sub

The syntax of the IIf function is:

IIf(true/false_clause, value_for_true, _
    value_for_false). 

Two interesting results of the fact that IIf is a function call are that IIf c