1.5 Unique Language Features

This section covers features that are specific to each language. Throughout the book I have been pointing out things that are in one language and not in the other if the other language at least has a feature that remotely resembles that of the first. This section covers things in each language that are not really available in the other.

1.5.1 Unsafe Blocks (C#)

Perhaps the biggest difference between C# and VB.NET is that C# enables developers to write blocks of unsafe code. Unsafe blocks (or unmanaged blocks) are mainly used to access API functions or COM functions that require pointers and enable C# developers to manipulate memory directly through pointers. In C#, it is illegal to use pointers unless the code is inside an unsafe block.

Most of the time, C# developers will not use unsafe blocks, since unsafe code can't be verified and therefore requires much higher security rights than code that can be verified to be safe. The following shows an example of unsafe code:

figs/csharpicon.gif
 
class Class1
{
   static unsafe void Main(string[] args)
   {
      //who says strings cannot be changed
      string sName = "Joseph Mojica";
        
      fixed (char *Temp = sName)
      {
         char *ch = Temp;
         ch += 4;
         *ch = (char)0;
         ch += 1;
         *ch = (char)0;
      }
  
      System.Console.WriteLine(sName);
   }
}

This code accesses the buffer of a string variable directly and changes two characters. Normally, strings are immutable, but with unsafe code, you can manipulate memory directly. Notice that the function needs to be marked as unsafe. Also notice the use of the fixed keyword. fixed pins a variable to a certain location of memory so that if garbage collection occurs, the collector will not move the contents of memory that the variable points to to another location.

1.5.2 using (C#)

Because .NET reclaims memory using garbage collection, an object may not be released for a while, even if there are no variables pointing to it. Sometimes, however, it is good to deallocate expensive resources right away rather than waiting for the garbage collector. A good example of this is an ADO.NET Connection object, which potentially keeps a handle to a SQL Server connection. Connections are expensive resources and should be reclaimed as soon as possible. For that reason, the .NET framework defines the IDisposable interface. You can ask an object if it supports IDisposable, then call the interface's Dispose method. In the implementation of Dispose, the author of the object with the expensive resource should release the resource. A good programming practice is to write code that uses objects with expensive resources inside a try...finally block, and in the finally section of the block to add code to ask for IDisposable and call Dispose. This is done so that if by some chance there is an exception in the code, the finally block will always take care of calling Dispose.

C# has a construct called using that writes this code automatically; it generates IL to enclose the code for an object inside a try...finally block, and to call the Dispose method on the object before exiting the block of code. Let's see first what the code would look like without the using function in both C# and VB.NET. Then we will see what it looks like with the using function.

figs/csharpicon.gif
 
void OpenDatabase(  )
{
  string cstr = 
      "Provider=Microsoft.Jet.OLEDB.4.0;";
  cstr += "Data Source=c:\\csvqs.mdb;";
  OleDbConnection conn = new 
                    OleDbConnection(cstr);
  try 
  {
    conn.Open(  );
    //do something useful here
  }
  finally
  {
     IDisposable disp = conn 
                      as IDisposable;
     if (disp!=null) disp.Dispose(  );
  }
}

This code opens a connection to an Access database and then is supposed to do something useful with the connection. If something goes wrong, however, or if the code exits normally, the code within the finally block will ensure that the Dispose method is called. The same is possible in VB.NET with the following:

figs/vbicon.gif
 
Sub OpenDatabase(  )
  Dim connstr As String
  connstr = "Provider=Microsoft.Jet.OLEDB.4.0;"
  connstr &= "Data Source=c:\\csvqs.mdb;"
  Dim conn As New OleDbConnection(connstr)
  Try 
    conn.Open(  )
    'do something useful here
  Finally
    Dim disp As IDisposable
    If TypeOf conn Is IDisposable Then
        disp = conn
        disp.Dispose(  )
    End If
  End Try
End Sub

Again, just as in C#, the Dispose code is inside a Finally block so that it always executes. Now let's see how this is more easily done in C# with the using command:

figs/csharpicon.gif
 
void OpenDatabase(  )
{
  string cstr;
  cstr = "Provider=Microsoft.Jet.OLEDB.4.0;";
  cstr += "Data Source=c:\\csvqs.mdb;";
  using (OleDbConnection conn = 
         new OleDbConnection(cstr))
  {
    conn.Open(  );
  }
}

With using, you can either declare a variable inside the using statement or use an existing variable. Before the code exits the using block, it will call the Dispose method on the object. The only way to do this in VB is to write the try...finally block by hand.

1.5.3 Documentation Comments (C#)

C# supports documentation comments, which are enhanced comments. They use three slashes (///) instead of two as the comment symbol and also use various XML tags. (The complete list of XML tags is in the Visual Studio .NET documentation under "Tags for Documentation Comments.") The compiler then searches through the code for those special comments and turns them into XML or even HTML documentation. Let's see some sample code:

figs/csharpicon.gif
 
/// <summary>
/// Adds a certain amount of money 
/// to the account's balance.
/// </summary>
/// <param name="Amount">The Amount 
/// parameter contains the amount to 
/// deposit.</param>
/// <returns>Total balance</returns>
public int MakeDeposit(int Amount)
{
    _Balance+=Amount;
    return _Balance;
}

The function is MakeDeposit. The documentation comments are found above the function. The code uses three tags: <summary> to describe the function, <param> to describe a parameter, and <returns> to describe the return parameter. One nice feature in VS .NET is that you can write the function first, then type /// above the function declaration. VS .NET then automatically writes the skeleton of the documentation tags with a <summary> tag, a <param> tag for each parameter, and a <returns> tag.

You then have to turn on the XML documentation feature for your project. You do that by specifying an output filename for the documentation in Project Properties figs/U2192.gifConfiguration Properties figs/U2192.gifBuild figs/U2192.gifXML Documentation File. If you name the XML Documentation File the same as your assembly and put it in the same directory as the assembly, the comments will appear in Intellisense when you reference the assembly.

Interestingly, if you turn on XML Documentation, the compiler will issue warnings for any public class that does not have XML Documentation information.

1.5.4 Operator Overloading (C#)

There is a feature in C# called operator overloading, which enables you to redefine operators (such as the plus operator) for a class. In other words, you can redefine what it means to add two instances of your class. There are a number of unary and binary operators you can override. (For a complete list of operators see "C# Operators" in the Visual Studio .NET documentation.)

When you overload operators, you always add a public static function followed by the type it returns (normally the same type as the class for which you are writing the overloaded operator function), followed by the operator keyword and the operator you are overloading.

For the following examples, assume that the functions are inside a class called Checking. The following code overloads the ++ unary operator:

figs/csharpicon.gif
 
public static Checking operator ++ 
              (Checking source)
{
   source._Balance++;
   return source;
}

A unary operator accepts one parameter of the type of the class for which the overloaded function belongs. In this example, we redefine the ++ operator to mean "add one to the balance of the account."

Here is an example of overloading a binary operator:

figs/csharpicon.gif
 
public static Checking operator + 
              (Checking source, int Amount)
{
   source._Balance += Amount;
   return source;
}

Binary operators require two parameters, one for the type for which the operator overloading function is written, while the second can usually be of any type. This example defines what happens when you add an integer to a Checking object. The function adds the integer to the overall balance. In fact, here is some code that shows how one would use the + operator in the class:

figs/csharpicon.gif
 
private void Form1_Load(object sender, System.EventArgs e)
{
    Checking check = new Checking(  );
    check+=100;
}

This code creates an instance of the Checking class, then adds 100 to the object. Adding 100 causes the code for the + operator to trigger.

There is no way to overload operators in VB.

Inside the IL

When you overload operators, the C# compiler renames the function to op_thenameofoperator. For example:

public static class Checking  op_Increment(class 
Checking source)
public static class Checking  op_Addition(class 
Checking source, int32 Amount)

If a developer writes code that uses the operator, like Check++, the compiler changes that code into a method call to one of the op_something functions, in this case op_Increment. If you use another language, like VB, that doesn't recognize operator overloading, the overloaded operator function appears like any other function, but with the name op_something. In fact, you can call the operator overloaded functions from VB using the op_something name.

1.5.5 Late Binding (VB)

One of the biggest features that VB has that C# does not have is late binding. In the COM days, late binding meant using the IDispatch interface for an object. In .NET, late binding has nothing to do with IDispatch, but involves using the .NET reflection functions. With reflection, a developer can inspect an object at runtime and find out all the methods the object supports as well as the parameters required to make the calls. Reflection is not just for making method calls; it enables the developer to find out almost anything about a class: fields, methods, properties, events, constructors, etc.

Both languages enable you to use the reflection functions directly. Here is an example in C# that invokes the MakeDeposit method in the Checking class:

figs/csharpicon.gif
 
public class Checking
{
   int _Balance;
  
   public void MakeDeposit(int Amount)
   {
      _Balance += Amount;
   }
}
  
class App
{
   static void Main(string[] args)
   {
      Checking check = new Checking(  );
      Type t = typeof(Checking);
      System.Reflection.MethodInfo mi = 
               t.GetMethod("MakeDeposit");
      object[] pars = new Object[] {100};
      mi.Invoke(check,pars);
   }
}

In this code, we first obtain a Type object. The Type object is the entry point to the reflection information. We then call the Type object's GetMethod function to retrieve a MethodInfo object containing information on the Checking class' MakeDeposit method. This is simplified by the fact that the Checking class has only one MakeDeposit method; if it had overloaded versions of MakeDeposit, we would have to tell it which overloaded version we wanted. Once you retrieve a MethodInfo object, you can call its Invoke method, passing an instance of the object and an array of objects with the values for the parameters of the function to be invoked. Invoke then makes the actual method call.

You can convert this code to VB. However, unlike C#, VB offers a mechanism for using reflection without using the reflection functions; it is called late binding. Take a look at the following code:

figs/vbicon.gif
 
Option Strict Off
Dim check As Object = New Checking()
check.MakeDeposit(100)

For this to work, you must turn off Option Strict. Then you declare a variable of type Object and assign it to any object or structure. You can then write code that invokes any public method in the object or structure, passing any number of parameters. The compiler turns that code into a call to one of the VB helper functions that uses reflection to make the actual method call.