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#.
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:
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 FunctionEnd Class Module AppSub Main( )
Dim acct As Object = New Account( ) System.Console.WriteLine(acct.ToString( )) End SubEnd 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.
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#:
//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:
stringsName //variable= //operatorsFirstName //first name+ //plus operatorsLastName; //semicolon signals the end of a statement
You can do the same with string literals if you precede the string with the @ symbol:
stringsName = @"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:
'one line in VBDim 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.)
'one line in VBDim _sName _As _String _= _sFirstName _+ _sLastName
Unlike C#, it is illegal to break up string literals into two separate lines.
C# distinguishes between single line comments and block comments. Single line comments use a double slash, as follows:
//This is a commentvoid 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:
/* Function: MakeDepositScope: PublicDescription: 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:
/*//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:
'This is a commentRem This is another commentSub MakeDeposit(ByVal Amount As Integer) Dim _Balance As Integer 'Account balanceEnd 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#.
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:
namespace WidgetsUSA{ namespace Banking { public class Checking { } public class Savings { } }}
The same code can be written in VB as follows:
Namespace WidgetsUSA Namespace Banking Class Checking End Class Class Savings End Class End NamespaceEnd 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:
using WidgetsUSA.Banking;class App{ static void Main( ) { Checking check = new Checking( ); }}
The equivalent of using in VB is Imports:
Imports WidgetsUSA.BankingClass App Shared Sub Main( ) Dim check As Checking = New Checking( ) End SubEnd 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:
Imports MyCompany.SharedCode.DatabaseClassesImports SomeOtherCompany.Modem Class App Shared Sub Main( ) Dim cn As Connection End SubEnd 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:
using db=MyCompany.SharedCode.DatabaseClasses;using SomeOtherCompany.Modem; class App{ static void Main( ) { db.Connection cn; }}
Here is the equivalent code in VB.NET:
Imports db=MyCompany.SharedCode.DatabaseClassesImports SomeOtherCompany.Modem Class App Shared Sub Main( ) Dim cn As db.Connection End SubEnd 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:
Imports Microsoft.VisualBasic.ControlChars Module App Sub Main( ) Dim s As String = "Hello" + NewLine + "World" System.Console.WriteLine(s) End SubEnd 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.
In C#, the variable type always precedes the variable name. Here are some examples:
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:
Dim x As IntegerDim y As DecimalDim z As RectangleDim obj As Object
Both languages enable you to create an instance of a class using the new keyword. Here are some examples in C#:
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:
Class AccountEnd 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 SubEnd 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.
C# requires you to initialize local variables explicitly. Consider the following declaration:
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:
Class Account Dim Balance As Integer Sub MakeDeposit( ) Dim tempBalance As Integer 'no compiler error System.Console.WriteLine(tempBalance) End SubEnd Class
In this example, both Balance and tempBalance are initialized to 0.
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#:
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:
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:
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:
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:
Imports System.Runtime.InteropServicesSub 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.
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:
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:
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 SubEnd 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.
In VB, you specify optional parameters as follows:
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#:
using System.Runtime.InteropServices;public void MakeDeposit([Optional] int Amount){}
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:
//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 argumentsacct.MakeDeposit(50,100,20,30);//a call with no argumentsacct.MakeDeposit( );//a call with an array argumentint[] 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:
'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 parametersacct.MakeDeposit(50,100,20,30)'a call with no parametersacct.MakeDeposit( )'here is a call with an array, also acceptableDim amts As Integer( ) = { 100, 200, 30, 50 }acct.MakeDeposit(amts)
In C#, all methods are functions. Some functions return nothing (void), as in the following:
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:
Sub MakeDeposit(ByVal Amount As Integer)End Sub Function IsOpen(ByVal AcctID As Integer) As BooleanEnd Function
Notice that in a function you add As after the parameter list, followed by the return type.
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:
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.)
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 FunctionEnd Class
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:
class App{ static void Main( ) {}
}
Class App Shared Sub Main( ) End SubEnd 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:
class App{ static void Main(string[] args) { foreach(string arg in args) {System.Console.WriteLine(arg);
}
}
}
Class App Shared Sub Main(ByVal args As String( )) Dim arg As String For Each arg In args System.Console.WriteLine(arg) Next End SubEnd 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:
param1param2/param3param4 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:
class App{ static int Main( ) {return 0;
}
}
Class App Shared Function Main( ) As Integer Return 0 End FunctionEnd 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:
Imports Microsoft.VisualBasic Class App Shared Sub Main( ) Dim args As String = Command( ) System.Console.WriteLine(args) End SubEnd Class
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:
Module App Sub CheckSecurity(ByVal sID As String) If sID = "" Then End End If End Sub Sub Main( ) CheckSecurity("") End SubEnd 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:
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:
Function MakeDeposit(ByVal Amount As Integer) As Integer If Amount < 0 Then Exit Function End If m_Balance += Amount Return m_BalanceEnd 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:
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 SubEnd 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:
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:
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.
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:
|
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.
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:
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:
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:
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:
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 SubEnd 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:
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 SubEnd Class
As the example shows, it is legal to invoke the GetNextAccountID function using the class name or an instance of the Account class.
VB.NET supports code modules, which developers use to write libraries of global functions. For example:
Module App Sub Main( ) End SubEnd 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:
Class Math Shared Function Add(Num1 As Integer, _ Num2 As Integer) As Integer End FunctionEnd Class Module App Sub Main( ) System.Console.WriteLine(Math.Add(3,4)) End SubEnd 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:
Module Math Function Add(Num1 As Integer, _ Num2 As Integer) As Integer End FunctionEnd Module Module App Sub Main( ) System.Console.WriteLine(Add(3,4)) End SubEnd 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:
[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.
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:
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:
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:
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:
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:
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:
'when using "End If" the "Then" is optional'but VS.NET adds it by defaultIf 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:
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:
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:
|
C# |
Operator |
|
|
And |
&& |
and |
|
Or |
|| |
or |
|
Not |
! |
Boolean opposite |
|
= |
== |
equals |
|
<> |
!= |
not equal |
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:
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:
Shared Function DoTask1( ) As Boolean Return TrueEnd Function Shared Function DoTask2( ) As Boolean Return FalseEnd 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 IfEnd 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:
Shared Function DoTask1( ) As Boolean Return TrueEnd Function Shared Function DoTask2( ) As Boolean Return FalseEnd Function Shared Sub Main( ) If DoTask1() OrElse DoTask2( ) End If If DoTask2() AndAlso DoTask1( ) End IfEnd 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.
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:
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:
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