Home > Articles > Programming > Windows Programming

The .NET Languages

  • Print
  • + Share This
  • 💬 Discuss
This chapter focuses on the foundations of .NET programming. It starts with a language primer on the basics; it then covers some more in-depth programming features and language-related IDE enhancements. The chapter concludes with an overview and map of the .NET Framework class library.

Unlocking the productivity promises of the Visual Studio IDE is at the heart of this book. The IDE, of course, also ships from Microsoft in concert with new versions of the .NET languages and Framework. You need to have a solid grasp of programming the Visual Basic or C# language using the .NET Framework to take advantage of everything Visual Studio has to offer.

In this chapter, we set aside the IDE (for the most part) and focus on the foundations of .NET programming. We start with a language primer on the basics; we then cover some more in-depth programming features and language-related IDE enhancements. The chapter concludes with an overview and map of the .NET Framework class library.

Language Primer

You have a few language choices available to you as a .NET programmer: Visual Basic, C#, C++, or F#. Which you choose is typically a result of your history, style, and intent. Developers who have worked with past incarnations of VB or another basic language will find they are at home inside Visual Basic. The language (including templates, tools, wizards, and so on) is all about developer productivity. Developers whose roots are in a C-based language (C++, Java, and so on) and want similar productivity in a straightforward way gravitate toward C#. Of course, some developers will just want to stay in C++ even for their .NET applications.

Visual Studio 2010 saw the introduction of the F# language. This language has been available in various states previously; however, it is now part of the full Visual Studio product line. Similar to other .NET languages, F# supports object-oriented programming. What makes it different is that it is also a functional programming language. Functional programming elevates functions to first-class values. (The F in F# is for functional.) For example, a functional language allows you to easily pass functions as parameters, return functions as the result of a function, chain functions together to create new functions, create recursive functions, and more. These powerful features in F# allow you to more easily tackle complex algorithms with less code (and often less pain) than it would take with the standard object-oriented (OO)-only languages of Visual Basic and C#. Having F# inside of Visual Studio also means that you can leverage the .NET Framework, get the benefits of the Common Language Runtime (CLR) (including calling to and from other .NET code), and have debugging and other related tools support.

Programming Objects

Programming in .NET is an object-oriented experience. You write your own classes and leverage those created by Microsoft (forms, controls, and libraries). In fact, every .NET application has at least one class, and more often it has hundreds. You can extend classes with new functionality (inheritance), define classes based on a contract (interface), and override the behavior of existing classes (polymorphism). This section looks at defining objects with .NET code.

Classes

Think of classes as the container for your code. Classes define how you hold data (properties) and perform actions (methods); they communicate how your class works after it’s created (instantiated). When you create an instance of the class, it is an object and can then actually maintain data and execute code.

You define a class using the Class keyword. The following shows an example:

C#
public class Employee
{
}

VB

Public Class Employee

End Class

Fields and Properties

You add code to a class to define its data and behavior. Data for your class can be stored in fields or properties. Fields and properties are similar; both define data that is contained in the class. The difference is that properties can provide a means to protect the access (setting and getting) to field data. Fields are typically private variables defined at the class level and are thus defined as follows:

C#
public class Employee
{
  private string _name;
}

VB

Public Class Employee
  Private _name As String
End Class

You can define public fields on your class. In this case, they are accessible members from the class. However, it is a best practice to encapsulate public data inside a property. This way you can control whether to expose the ability to read or write a property. You then also control the reading and writing of the data. Properties are typically backed by an internal, private field. This is called data hiding and is implemented with the Private keyword. For example, the previously defined field can be encapsulated into a property as follows:

C#
public class Employee
{
  private string _name;

  public string Name
  {
    get { return _name; }
    set { _name = value; }
  }
}
VB
Public Class Employee
    Private _name As String

    Public Property Name() As String
        Get
            Return _name
        End Get
        Set(ByVal value As String)
            _name = value
        End Set
    End Property
End Class

You can also create read-only properties. This is useful when you want to reserve the writing of the property’s value to code running inside the class. You create a read-only property by not implementing the set statement in the property definition. In VB, you also have to add the ReadOnly keyword. For example, suppose you want to add an Id property to the Employee class defined previously. This Id can be read but only set by internal class code. You could implement a read-only property as follows:

C#
private int _id;

public int Id
{
  get { return _id; }
}

VB

Private _id As Integer
Public ReadOnly Property Id() As Integer
  Get
    Return _id
  End Get
End Property

Methods

Methods represent the blocks of code in your class that, when called, perform some specific action. This action could be reading or writing from a database, calling other methods, calculating a value, processing some business rules and returning a result, or whatever you need your code to do.

Methods are defined by their names and access levels; see the next section for more details on access levels. In VB, you also need to add the Sub keyword to define a method that does not return a value. In C#, this is done by indicating the return type of void before the method name. For example, if you were to add a Save method to the Employee class previously defined, the code would look like this:

C#
public void Save()
{
  //implementation code goes here
}

VB

Public Sub Save()
  'implementation code goes here
End Sub

Methods often return values to the code that called the method. To define a method that returns a value, you must indicate the method’s return type (the class type of the returned data). In VB, you also use the keyword Function (instead of Sub). You use the Return keyword to indicate the value to return from your code. For example, if you were to add a method to calculate an employee’s remaining sick day, you would do so as follows:

C#
public int GetRemainingSickDays()
{
  int _sickDays = 0;

  //calculate remaining sick days

  return _sickDays;
}

VB

Function GetRemainingSickDays() As Integer

  Dim _sickDays As Integer = 0

  'code to calculate remaining sick days

  Return _sickDays

End Function

In this example, note the return type defined in the method signature (first line of the method). Also note the use of the keyword Return to return a value from the method. In this case, that value is stored inside a variable defined as internal to the method.

Member Accessibility

The properties, fields, and methods in your application are referred to as class members. Each member in your class is defined to have a specific access level. As you’ve seen, if you want others to be able to access a member you must declare that member as public. If you want to reserve the member for accessibility only within the class, you declare it as private. These are two of the member accessibility levels available to you. The full complement of accessibility levels are described in Table 3.1.

Table 3.1. Member Accessibility Level in .NET

Level

Description

Public

Indicates that a member is publicly available to any code that has access to the class.

Private

Indicates that the member is hidden and private to the class that contains the member. No code outside the class can directly access members defined as private.

Protected

Protected is similar to private. It indicates that the member is not exposed publicly. Rather, it is private to the class. However, protected members are also made available to any class that derives from the class that contains the protected method. (See the “Inheritance” section for more details.)

Internal

Indicates that a member is available to all code within the assembly that contains it. This means other classes within a compiled .dll or .exe can access the member. However, other assemblies that reference a given .dll cannot access internal members.

Protected Internal

Indicates that the member is accessible by all code within an assembly and any code that derives from a class that contains the given member.

In addition to class-member accessibility, classes themselves also use the same accessibility levels. You can declare a class as public, private, protected, and so on to define your intended usage. You want to make many classes private or protected to the class and deriving types. The classes you make public define the functionality you want to expose to other code.

Constructors

A constructor is code that is called when a new instance of your class is created. This code is used to define how you want your class created, typically by setting default values or some related initialization code. You create a constructor as you would a method. The difference is that you give the constructor the same name as the class. The following code shows an example for the Employee class:

C#
public Employee()
{
  //init default values of an empty employee object
}

VB

Public Sub Employee()
  'init default values of an empty employee object
End Sub

A class can have multiple constructors to change the way in which the object is created. In these instances, each constructor is defined with a different set of parameters. The version of the constructor that does not take parameters is referred to as the default constructor. The following shows a couple additional constructors added to the Employee class. One initializes an Employee object based on the calling code passing in an id parameter; the other uses the employee’s email address to initialize the object:

C#
public Employee(int id)
{
  //init default values for the employee defined by the given id
}

public Employee(string emailAddress)
{
  //init default values for the employee defined by the given email
}

VB

Public Sub Employee(ByVal id As Integer)
  'init default values for the employee defined by the given id
End Sub

Public Sub Employee(ByVal emailAddress As String)
  'init default values for the employee defined by the given email
End Sub

Static (Shared in VB) Members and Objects

Sometimes you do not want the full behavior of a class for all of your methods. Instead, you might want to define certain methods that are not part of an object. These methods often retrieve information or calculate values but are not part of a specific object. In these cases, you can create entire classes or just specific methods of a class as static (or shared in VB).

The Shared and Static keywords, when applied to a method, indicate that the method can be called without creating an instance of the class that contains it. Shared and Static can also be defined at the class level. In this case, you are indicating that the class only contains shared and static methods, and it cannot be created as an instance. For example, you might add a static helper method to the Employee class to check to see whether an employee is active in the system before you create an instance. This declaration would look like this:

C#
public static bool IsActive(string emailAddress)
{
  //check to see if an employee has been added to the system
}

VB

Public Shared Function IsActive(ByVal emailAddress As String) As Boolean
  'check to see if an employee has been added to the system
End Function

Enumerations

Enumerations enable you to create a group of named values that help improve your code readability. Each item in an enumeration is a unique integer value. You can pass the enumeration value around as a name rather than an actual value. In this way, your code doesn’t rely on arbitrary, “magic” numbers. Instead, the code is sensible and readable.

You create an enumeration using the enum keyword. For example, you might add an enumeration to the Employee class to store the employment status of an employee. This would enable you to make decisions in your code based on the specific status of an employee. To define this enumeration, you add code as follows to the Employee class:

C#
enum EmploymentStatus
{
  Salaried,
  Hourly,
  Contract,
  Other
}

VB

Enum EmploymentStatus
  Salaried
  Hourly
  Contract
  Other
End Enum

Inheritance

You can define a new class based on an existing class, which is called inheritance. You use inheritance to extend (or add to) the functionality of a base class. Classes that that extend a base class are said to derive their functionality from another class. That is, they contain all the functionality of the base class plus any additional functionality added to the new class.

You indicate inheritance in VB by using the Inherits keyword; in C# you add a colon and the base class name following the name of the new class. For example, suppose you implement a Manager class that derives from Employee. The Manager class contains all the members of an Employee but might add special properties and methods specific to a Manager. You define this new class as follows:

C#
class Manager: Employee
{
}

VB

Public Class Manager
  Inherits Employee

End Class

Note that you can actually define a base class that cannot be created. Instead, it only exists to form the basis for a new class. Other classes can derive from it, but you cannot create a direct instance of just the base class. This is done by adding the MustInherit (VB) or Abstract (C#) keyword in front of the class definition. The keyword NotInheritable (VB) or Sealed (C#) indicates that the class cannot be used as the basis for a new class.

Overriding Behavior

When you design your classes, you might want to consider how other developers might extend them. That is, your classes might serve as the base class for future derived classes. If this is the case, you might also consider which (if any) features of your base class you want to allow a derived class to override. The derived class may then implement a new version of one of your base methods, for example. This process is often referred to as polymorphism in OO programming.

To change the data or behavior of a base class you can either add to the base class or you can override an existing member of the base class. Doing the latter gives you alternate behavior for the same function in your new class. You decide which members of your base class are available for override. You do so by marking them as virtual members; this indicates a derived class may fully replace your base class functionality.

For example, suppose that you want to enable the CalculateYearlyCost method of the Employee class to be overridden when the Employee is used as the base for the Manager class. In this case, the calculation for a Manager is different for that of an Employee. You therefore mark the method inside the Employee class as virtual (C#) or Overridable (VB), as follows:

C#
public class Employee
{
  public virtual float CalculateYearlyCost()
  {
  }
}

VB

Public Class Employee
  Public Overridable Function CalculateYearlyCost() As Single

  End Function
End Class

You can then override this method in the derived class. You do so using the override (C#) or Overrides (VB) keyword. You can still call the method on the base class if you need to by using the base (C#) or MyBase (VB) keyword. The following shows an example:

C#
class Manager : Employee
{
  public override float CalculateYearlyCost()
  {
    //add new functionality, access underlying method using base keyword
  }
}

VB

Public Class Manager
  Inherits Employee

  Public Overrides Function CalculateYearlyCost() As Single
    'add new functionality, access underlying method using MyBase
  End Function

End Class

Hiding Members

There is a second way you can override the functionality of a base class. This involves using the keyword new (C#) or Shadows (VB) to redefine the base method. Overriding in this manner hides the base class members. However, the base class member is still called if an instance of the derived class gets down-cast to an instance of the base class. This type of overriding is referred to as hiding by name. For example, you could replace the C# keyword override with new or the VB Overrides with Shadows to implement this type of behavior.

You need to be careful about hiding members versus overriding because down-casting can occur often. For example, you might be working with a collection of Employee objects (some of type Manager and some of type Employee). If you iterate over the list using the base class (for each employee), you get a different method called on the Manager class depending on if you hid the member (in which case, the base class method is called) or override the member (in which case, the derived class method is called).

Overloading Members

You can also create multiple versions of the same procedure. All versions of a procedure can be defined inside the same class or you can have a few versions in a base class and yet other versions in a derived class. This is useful when you need to preserve the name of the procedure but need to create different versions that each take different parameters. Creating multiple versions of a procedure is called overloading or hiding by signature (as in the method’s calling signature).

Overloading a method must follow rules designed to make each overload somehow different from all the others. Of course, each overload has the same name. However, you must change either the number of parameters the method accepts, the data type of one or more of those parameters, or the order of the parameters. You create a valid overload by changing one or more of these items to make the overload signature unique. Note that changing the return type, if the method returns a value, or a parameter modifier is not sufficient to create an overload.

For example, suppose you were creating a method to return the number of vacation days left for an employee. You might allow the users of this method to get the vacation days left for the current year, a supplied month, or a supplied month and year. In this case, the users of your method see a single method with multiple overloads. You implement this overloading similar to the following code:

C#
public short GetVacationUsed()
{
  //returns all vacation used in the current year
}

public short GetVacationUsed(short monthNumber)
{
  //returns all vacation used in the given month of the current year
}

public short GetVacationUsed(short monthNumber, short year)
{
  //returns all vacation used in the given month and year
}

VB

Public Function GetVacationUsed() As Short
  'returns all vacation used in the current year
End Function

Public Function GetVacationUsed(ByVal monthNumber As Short) As Short
  'returns all vacation used in the given month of the current year
End Function

Public Function GetVacationUsed(ByVal monthNumber As Short, ByVal year As Short) _
  As Short
  'returns all vacation used in the given month and year
End Function

Defining Interface Contracts

An interface is used to define a class contract. An interface does not contain any actual functioning code. Rather, it indicates a common structure for code that can be implemented by another class. This enables you to create common contracts and use those contracts across multiple objects. You can then trust that each class that implements the interface does so completely and in the same manner.

An interface can define different types of class members including fields, properties, methods, events, and the like. To create an interface, you use the Interface keyword. For example, suppose you want to define a basic interface for a person. The Employee class might then be required to implement this interface. Other objects (such as User and Customer) might also implement the same interface. The following shows an example of how you might define this interface:

C#
interface IPerson
{
    string Name();
    DateTime DateOfBirth();
    string EyeColor();
    short HeightInInches();
}

VB

Public Interface IPerson

  Property Name As String
  Property DateOfBirth As DateTime
  Property EyeColor As String
  Property HeightInInches As Short
End Interface

You implement the interface by adding the interface to the class definition on the class where you intend to implement the interface. In VB, this is done by adding the Implements keyword under the class definition (similar to inheritance). In C#, you add the interface to the class definition the same way you would indicate a base class (using a colon). You can separate multiple implemented interfaces by a comma.

Creating Structures

So far we have talked about programming classes. There is another type of class available to .NET programmers called a structure. Structures are similar to classes; they can contain properties, fields, enumerations, and methods; they can implement interfaces; they can have one or more constructors. The differences lie in how structures are managed by .NET.

Structures are considered value types. This means that when structures are used, the entire class is passed around as a value and not a reference. A class is a reference type. When you use a class and pass it around your application, you are actually passing a reference to a class. Not so with a structure. This also changes how .NET manages the memory used for structures and classes. Structures use stack allocation and classes are managed on the heap. To put this in perspective for .NET developers imagine you have an instance of an Employee class. This instance might be created inside one object and passed to another object’s method. If the second object makes a change to the Employee instance, this change is reflected inside all objects that maintain a reference to the instance. If this were a structure, however, there would be copies of that object passed around, and changes would be isolated to each copy.

There are other differences between classes and structures. For one, structures cannot be inherited from. They also have an implicit public constructor that cannot be redefined. For these reasons, structures are best used when you need a lightweight container for data values and do not need the features of a reference type. Structures are often used to define custom data types.

You define a structure much like you define a class. In place of the class keyword, however, you use struct (C#) or structure (VB). For example, imagine you want to define a data type that represents a paycheck. You could create a structure to hold this information. The following shows an example:

C#
public struct PayCheck
{
  private double _amount;

  public double Amount
  {
    get { return _amount; }
  }

  //add additional structure elements ...
}

VB

Public Structure Paycheck

  Private _amount As Double
  Public ReadOnly Property Amount() As Double
    Get
      Return _amount
    End Get
  End Property

  'additional structure elements ...

End Structure

Organizing Your Code with Namespaces

A namespaces is used to group code that is specific to a company, an application, or a given library. Namespaces help .NET programmers overcome naming conflicts for classes and methods. For instance, you cannot have two classes with the same name in the same namespace because it would confuse the .NET runtime and developers. Instead, your class names are unique inside your namespace.

You declare a namespace at the top of your code using the keyword namespace. Alternatively, you can set the default namespace inside your project properties. In this way, you do not have to see the outer namespace definition inside each code file. A common practice for defining namespaces includes using your company name followed by the application being written and then perhaps the library to which the code belongs. For example, you might define the namespace grouping for the Employee class as follows:

C#
namespace MyCompany.MyApplication.UserLibrary
{
  public class Employee
  {
  }
}

VB

Namespace MyCompany.MyApplication.UserLibrary

  Public Class Employee

  End Class

End Namespace

You do not have to add this namespace information at the top of every code file in your project. This can become redundant and is error prone as a developer might forget to include the namespace definition. As an alternative, you can set the root namespace for your entire project using the project properties window (right-click the project file and choose Properties). Figure 3.1 shows an example. This is a similar experience in both C# and VB. Note that you can define a root namespace here and still add additional namespace groupings in your code as necessary. Of course, those additional namespace definitions fall inside the root namespace.

Figure 3-1

Figure 3.1. Setting the root namespace at the project level.

You access code inside a namespace by using the fully qualified definition of the namespace. For example, the .NET root namespace is System. If you were to access the String class, you would do so by calling System.String. This is true for your code, too. To access the GetVacationUsed method, you might call out as follows:

MyCompany.MyApplication.User.Employee.GetVacationUsed()

As you can see, accessing code using the fully qualified namespace can be cumbersome in terms of typing and reading your code. Thankfully, you can import (with the using statement in C#) a namespace inside your code. This frees you from having to fully qualify each type call. Instead, the compiler resolves class names based on your imported namespaces. Of course, the namespaces themselves are still required to prevent ambiguity in the compiler. Importing namespaces also help trim IntelliSense to those imported libraries.

In most cases, you do not get conflicts with imported namespaces. Type names are typically different enough in a given library that they do not overlap. If names do overlap, you can add qualification to eliminate the conflict.

You import namespaces using the using statement (C#) or imports (VB) keyword. For example, the following shows namespaces imported into a class file for a Windows Forms application. The code includes the import statements for referencing the Employee class library:

C#
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using MyCompany.MyApplication.UserLibrary;

namespace TestHarnessCSharp
{
  public partial class Form1 : Form
  {
    public Form1()
    {
      InitializeComponent();
    }

    private void Form1_Load(object sender, EventArgs e)
    {
      Employee emp = new Employee();
      //do work
    }
  }
}

VB

Imports MyCompany.MyApplication.UserLibrary

Public Class Form1

  Private Sub Form1_Load(ByVal sender As System.Object, _
    ByVal e As System.EventArgs) Handles MyBase.Load

    Dim emp As New Employee()
    'do work ...

  End Sub

End Class

Notice in the preceding example that the C# code has a number of additional using (or imports) statements at the top of the file. This is because VB files automatically import many of the default namespaces in .NET.

Types, Variables, and Constants

All classes and interfaces you create in .NET are considered types. That is, they define a specific type of data. The underlying classes in the .NET Framework are also all strong types. In fact, the .NET languages of both C# and VB are based on strongly typed objects. This means when you define a variable you create an instance of a strongly typed class. The .NET runtime can then rely on this type information for handling casting, comparisons, and other rules.

Data Types

A number of built-in types (classes) are used for common programming needs. These built-in types are referred to as data types and represent things such as a string of characters or a numeric value. You work with these data types like you would any structure or class. You can declare a variable of a certain type, create a new instance, or execute a method off of the type.

Most of the simple data types you use are value types (structures). There are a couple reference data types (classes). These are string (System.String) and object (System.Object). Recall that value types store data (and copies of data) and that reference types are used to provide a reference to underlying data. Table 3.2 lists many of the common value types used in .NET programming; there are more than what is in this list. The list shows the underlying .NET Framework class, the range allowed in the data type, and the C# and VB data type names.

Table 3.2. Value Data Types by Language

.NET Framework

C# Data Type

VB Data Type

Range

System.Byte

byte

Byte

0 to 255

System.Int16

short

Short

-32,768 to 32,767

System.Int32

int

Integer

-2,147,483,648 to 2,147,483,647

System.Int64

long

Long

–9,223,372,036,854,775,808 to 9,223,372,036,854,775,807

System.Single

float

Single

±1.5 · 10–45 to ±3.4 · 1038

System.Double

double

Double

±5.0 · 10–324 to ±1.7 · 10308

System.Decimal

decimal

Decimal

±1.0 · 10–28 to ±7.9 · 1028

System.Boolean

bool

Boolean

true or false

Many of the data types listed in Table 3.2 include unsigned versions. These are preceded with a u. The System.Byte data type is the exception. It is unsigned. The signed version is called sbyte. Signed values include both the negative and positive numbers in their range. Unsigned value types start and zero and include only positive numeric values.

Declaring Variables

When you declare a variable using a simple type, you typically want to declare the variable using the type that represents the lowest possible range for your situation. For example, if you were to define a variable to hold the month value you might use System.Byte. If you were to define the year, you might use System.Int16. In this way, the lowest possible overhead is used for these types.

You declare a variable in C# by preceding the name of the variable with its type. In VB, you use the Dim statement. The type then comes after the variable’s name. The following code shows an example of declaring variables in each language:

C#
byte month;
short year;
float paycheckAmount;

VB

Dim month As Byte
Dim year As Short
Dim paycheckAmount As Single

Of course, you can also define variables of other (more complex) types in the .NET Framework or types defined in your own class libraries. When you declare a variable, you can also assign it a default value or instantiate a new instance. The following shows an example:

C#
byte month = 1;
short year = 2010;
float paycheckAmount = 0;
string name = "test";
Employee emp = new Employee();

VB

Dim month As Byte = 1
Dim year As Short = 2010
Dim paycheckAmount As Single = 0
Dim name As String = "test"
Dim emp As Employee = New Employee()

Type Conversion

Again, both VB and C# are strongly typed languages. Therefore, the variables you declare cannot be reused by assigning different type values. Rather, they must always represent the underlying type to which they were declared. This can be problematic. Sometimes, for instance, you have an integer that you need to pass to a method that only accepts a double. Or you need to parse a string value into an integer for a calculation. You might also have to convert a class to an interface type in order to use it with a specific method. These are all instances where you need to convert one type to another.

There are two conversions that you can make: implicit and explicit. An implicit conversion happens when you pass a smaller value type into a larger type that can contain the smaller value. In this case, if no data is lost the conversion is allowed. For example, you can pass a short into a long without issue. However, passing a float (or double) into an integer might result in data loss and is thus not allowed as an implicit conversion; you need to explicitly convert. For example, the following code converts an integer value to a double. This code does not throw a type conversion error. Rather, it converts using implicit conversion:

C#
int intVal = 100;
double doubleVal = intVal;

VB

Dim intVal As Integer = 100
Dim doubleVal As Double = intVal

If there is a chance that the conversion results in data loss, you must explicitly indicate your intention to convert types. This is called casting. You can also cast values that might otherwise be implicitly converted. In fact, this often makes your code more readable.

In C#, you cast a variable to another type by putting the type to which you are casting in parentheses in front of the type (or value) being cast as in the following:

C#
double doubleVal = 12.345;
int intVal = (int)doubleVal;

In VB, you cast a variable to another type using conversion keywords. These keywords have a C (for cast) in front of them followed by the type to which you are casting. For example, you can cast to an integer using CInt, or a double using CDbl, or a string using CStr. The following shows an example:

VB

Dim doubleVal As Double = 12.345
Dim intVal As Integer = CInt(doubleVal)

There are times when you have a string value and need to convert it into a numeric. This cast is not allowed. However, most of the numeric types include the method Parse that enables you to parse a string into a numeric value. There is also TryParse that returns a Boolean indicating whether the parse will work. The following code shows an example:

C#
string stringVal = "1234";
int intVal;
intVal = int.Parse(stringVal);

VB

Dim stringVal As String = "1234"
Dim intVal As Integer
intVal = Integer.Parse(stringVal)

The framework also includes the Convert class that enables you to convert one type to almost any other (including strings). This class is available to both VB and C# programmers.

Defining Constants

You might need to define values in your application that will not (and cannot) change during the execution of the application. In this case, you need to declare a constant. A constant in .NET is said to be an immutable value. That is, they cannot change values. You declare a constant in your code (typically at the class level) using the keyword, const. Like fields, they can be private or public. The following shows an example:

C#
private const int CompanyTaxNumber = 123456;

VB

Private Const CompanyTaxNumber As Integer = 123456

Understanding Operators

Operators are indicators in your code that express an operation to perform. An operator might be an assignment from one variable to another, a comparison between two values, or a mathematical calculation among values. There are many operators available to .NET programmers. We do not cover them all here, but many of the more common operators are discussed in the following sections.

Assignment

Assignment operators are used to assign one variable or value to another. The most simple example is the equal (=) operator. This simply assigns the value on the right of the operator to the variable on the left side of the assignment (as in x = y). Other operators enable you to do assignment with addition (+=), assignment with subtraction (-=), assignment with multiplication (*=), and assignment of a string value with concatenation (&=). There are also assignment operators for division, arithmetic shifting, and more. The following shows a few assignment code examples:

C#
public double CalculatePaycheck(double gross, double commission,
  double deductions)
{
  double paycheck = gross;  //define paycheck as gross pay
  paycheck += commission;   //add commission
  paycheck -= deductions;   //subtract deductions

  return paycheck;
}

VB

Public Function CalculatePaycheck(ByVal gross As Double, _
  ByVal commission As Double, ByVal deductions As Double)

  Dim paycheck As Double = gross  'define paycheck as gross pay
  paycheck += commission          'add commission
  paycheck -= deductions          'subtract deductions

  Return paycheck
End Function

Arithmetic

The arithmetic operations enable you to perform calculations on variables and using values. For example, you can use the multiplication operator (*) to multiply two numbers (x * y). The operators you expect are all available, such as addition (+), subtraction (-), division to return an integer (\), division to return a floating point (/), multiplication (*), and dividing for remainder (mod in VB, % in C#). There are other less-common operators, too.

You typically use assignment with arithmetic operators, as in x = y * z. However, you can use the value of the calculation when making decisions in your code (without first assigning it to a variable); there’s more on this in the coming sections. As an example of basic arithmetic in code with assignment, the following code shows how you might calculate an employee’s accrued vacations days at the given point in the year. (The AccrualRate is either a constant or set based on the number of days of vacation an employee has.)

C#
double accruedVacation = DateTime.Today.DayOfYear * AccrualRate;

VB

Dim accruedVacation as Double = DateTime.Today.DayOfYear * AccrualRate

Comparison

The comparison operators enable you to determine whether values are equal to one another, greater than, or less than. You typically use these operators comparing two variables, values, or expressions. The results of the comparison indicate whether or not (true or false) the comparison is valid (as in is x > y). The comparison operators include less than (<), less than or equal to (<=), greater than (>), greater than or equal to (>=), equal (= in VB and == in C#), and does not equal (<> in VB and != in C#). The following shows an example of assigning a variable of type Boolean to a comparison result:

C#
bool check = accruedVacation > vacationTakenToDate;

VB

Dim check As Boolean = accruedVacation > vacationTakenToDate

You can also do type comparison to check to see whether two objects point to the same reference (or not). In C#, this type of comparison is still done with the equal (=) and not equal (!=) operators. In VB, you use the keywords Is and IsNot, as in check = Employee1 Is Employee2.

Concatenation

The concatenation operations enable you to combine string values. In VB, the concatenation operator is an ampersand (&) sign used with two string variables or values. In C#, the plus (+) sign is used. The following shows an example:

C#
string fullName = firstName + " " + lastName;

VB

Dim fullName as String = firstName & " " & lastName

Logical and Conditional

The logical and conditional operators enable you to combine comparisons in different ways to help make decisions in your code. (See the next section for even more details.) For example, you might combine two comparisons to make sure they are both true. Alternatively, you might need to determine if at least one of the two comparisons is true. You can do this and more with the logical operators. Table 3.3 lists many of the logical operators. (For code examples, see the next section.)

Table 3.3. Logical and Conditional Comparison Operators

Purpose

C#

VB

Pseudo Code Example

Join two Boolean expressions and get the result, as in result is true if both this and that are true.

&

And

VB: check = (x>Y) And (x>0) C#: check = (x>Y) && (x>0)

Negate a Boolean value or expression, as in results equal the opposite of an evaluation.

!

Not

VB: check = Not someVal C#: check = !someVal

Choose between one or another values, as in result is true if that or that is true.

|

Or

VB: check = (x>y) Or (x>0) C#: check = (x>y) | (x>0)

Two values must evaluate to opposite values, as in result is true if this is true and that is false.

^

Xor

VB: check = True Xor False C#: check = true ^ false

A short-circuited version of And where if the first condition does not pass evaluation, the second condition does not get executed.

&&

AndAlso

VB: check = (x>Y) AndAlso (x>0) C#: check = (x>Y) && (x>0)

A short-circuited version of Or where if the first condition does not pass evaluation, then the second condition does not get executed.

||

OrElse

VB: check = (x>y) OrElse (x>0) C#: check = (x>y) | (x>0)

Making Decisions and Branching Code

You can use the operators discussed previously to test for specific conditions in your code. These tests are then evaluated in order to make a decision on what code to execute or where to branch off in your application. There are three primary decision structures in .NET programming: If...Then...Else, Select...Case, and Try...Catch...Finally (as covered in the “Handling Errors” section later in this chapter).

If...Then...Else

You can use the If syntax in your code to test one or more conditions. Based on the results of your test, you might decide to execute one set of code if the condition proves true and another set of code if the condition proves false. You can also get into more complex scenarios by nesting If statements and using the logical operators discussed in the prior section.

In VB, you use the explicit If...Then statements nested with End If. In C#, you put your If conditions inside parentheses and the statements nested inside brackets. For example, the following shows code to determine whether an employee can get her vacation request approved. In this code, there is a nested if statement and an example of combining two conditions with and:

C#
public bool CanApproveVacationRequest(int daysRequested, int daysTaken,
  int daysAllowed, int daysAccruedToDate)
{
  //rule: employee can take vacation if it is accrued and not used
  if ((daysRequested < daysAllowed) & (daysTaken < daysAllowed))
  {
    if ((daysTaken + daysRequested) < daysAccruedToDate)
    {
      return true;
    } else {
      return false;
    }
  } else {
    return false;
  }
}

VB

Public Function CanApproveVacationRequest(ByVal daysRequested As Integer,
  ByVal daysTaken As Integer, ByVal daysAllowed As Integer,
  ByVal daysAccruedToDate As Integer) As Boolean

  'rule: employee can take vacation if it is accrued and not used
  If daysRequested < daysAllowed And daysTaken < daysAllowed Then
    If (daysTaken + daysRequested) < daysAccruedToDate Then
      Return True
    Else
      Return False
    End If
  Else
    Return False
  End If
End Function

Note that in VB if you have a single line that executes based on an if condition you can write that as a single line of code, as in If x > 500 Then doSomething. In C#, if you have a single line that executes, you can eliminate the need for the braces, and the statement following the If condition is executed based on the condition’s evaluation.

Select...Case (Switch)

The Select...Case (switch in C#) code construct enables you to evaluate a single statement for a value. Based on this condition, you then can execute blocks of code depending on the value.

In C#, you define the condition inside parentheses following the keyword switch. You then define each case block with the keyword case, the value you are checking on, and a colon. You must then add a break statement at the end of the case to indicate the end of the case. You can use the default keyword to execute code if no case was realized. The following code shows an example:

C#

private void CalculateAdditionalCompensation()
{
  switch (this.Status)
  {
    case EmploymentStatus.Contract:
      //code for contract employees
      break;
    case EmploymentStatus.Hourly:
      //code for hourly employees
      break;
    case EmploymentStatus.Salaried:
      //code for salaried employees
      break;
    case EmploymentStatus.SalariedCommissioned:
      //code for commissioned employees
      break;
    case EmploymentStatus.Other:
      //code for other employees
      break;
    default:
      //code that runs if bad status was set
      break;
   }
}

In VB, you write case Select...Case statements using the keyword Select followed by Case followed by the condition. Each condition is then preceded with Case. You can use Case Else to run code when no other condition value evaluates. Here is a code example:

VB

Private Sub CalculateAdditionalCompensation()

  Select Case Me.Status
    Case EmploymentStatus.Contract
      'code for contract employees

    Case EmploymentStatus.Hourly
      'code for hourly employees

    Case EmploymentStatus.Salaried
      'code for salaried employees

    Case EmploymentStatus.SalariedCommissioned
      'code for commissioned employees

    Case EmploymentStatus.Other
      'code for other employees

    Case Else
      'code that runs if bad status was set

  End Select

End Sub

Looping

There are many times in your code when you need to execute a set of statements more than once. In these cases, you need to create a loop. The most common scenarios are looping through code a set number of times, looping until a condition becomes true or false, or looping through code once per element in a collection of objects. (See the section “Working with Groups of Items” later in this chapter.)

For...Next

The For...Next construct enables you to execute a block of code statements a set number of times. This is accomplished through a counter that increments a set number of steps each time the loop executes. After the counter has reached a max value, the looping completes.

In C#, you write a for statement inside parentheses. The for statement has three parts: counter declaration, condition for the counter, and counting step. Each part is separated by a semicolon. The following code shows an example of executing a code block once for each employee’s direct report:

C#
for (int i = 0; i < numDirectReports; i++)
{
  //update employee based on num of direct report
}

In VB, your For statement is a little more readable. You indicate the counter, the initial value, and the To value. Optionally, you can add the Step keyword to indicate how many times you want to increment the counter each time through the loop. Here is a code example:

VB

For i As Integer = 1 To numDirectReports
  'update employee based on num of direct reports
Next

For...Each (Iterators)

Like For...Next, the For...Each construct enables you to execute a group of statements. However, For...Each executes once for each element in a group of elements (or a collection). For instance, if you add a block of code to the Employee class that needs to execute once for each DirectReport you could do so using the For...Next (as shown previously) and the execute based on the count of DirectReports. However, using For...Each allows you to iterate over each object in a collection. As you do, you get a reference to the given object that you can use in your code. This makes coding a little easier to write and to understand.

You implement For...Each similar as For...Next in both C# and VB. The following shows code that executes once for each Employee instance inside the collection DirectReports:

C#
foreach (Employee emp in DirectReports)
{
  //execute code based on each direct report
  //  using the item as in emp.Name
}

VB

For Each emp As Employee In DirectReports
  'execute code based on each direct report
  '  using the item as in emp.Name
Next

Do...While/Until

Sometimes you need to repeat a block of code as many times as required until a condition evaluates to true or false. You might be looking for a specific value or might be using a counter that increments based on logic (instead of standard steps). In these cases, you can use a Do...While or a While loop. A Do...While loop executes once before the condition is evaluated to determine whether it should execute a second time. A While loop evaluates the condition first and then only executes if the condition evaluates to true.

In C#, you can create Do...While loops using the do keyword followed by your block of code in braces. The while statement is written at the end of the code block indicating that the statements are executed once before looping. (Use a while loop to evaluate a condition before looping.) The following shows an example:

C#
do
{
  //get next project and calculate commission
  projectCommission = GetNextProjectCommision(empId);
  calculatedCommission += projectCommission;
  if (projectCommission == 0)
  break;
} while (calculatedCommission < MaxMonthlyCommission);

Notice in this code the use of the break keyword. This indicates that the code should break out of the Do...While loop. You can also use the continue keyword to skip remaining code in your code block and jump right to the while statement to force a condition evaluation (and possible another loop).

In VB, you can define the while (or until) statement at the top or bottom of the loop. If defined at the top, your statement is evaluated before the loop executes once. If at the bottom, the loop executes at least once before the statement is evaluated. The While keyword indicates that you want to loop while a condition is true (until it becomes false). The Until keyword allows you to loop until a condition evaluates to true (while it is false). The following shows an example:

VB

Do
  'get next project and calculate commission
  projectCommission = GetNextProjectCommision(empId)
  calculatedCommission += projectCommission
  If projectCommission = 0 Then Exit Do
Loop While calculatedCommission < MaxMonthlyCommission

As mentioned before, there is also the basic While loop (without do). This simply loops a block of code while a condition evaluates to true. Also, like all looping constructs, you can nest Do...While loops to handle more complex situations.

Working with Groups of Items

A common scenario in computer programming is managing a group of similar items. For example, you might need to work with a set of values, such as ZIP Codes to which a sales representative is assigned. Alternatively, you might need to work with a group of objects such as the paychecks an employee has received in a given year. In cases where you need to work with a group of elements, you can do so using an array or a collection class. The former is great for working with a set sequential list of items of the same type. The latter is more applicable for managing a variable-sized group of objects.

Arrays

An array is a group of items of the same type (either value or reference types). For instance, you might create an array that contains all integer values or all string values. You also have to define the number of elements contained in your array when you first initialize it. There are ways to expand or contract this size, but these typically involve copying the array into another array. If you need the flexibility of adding and removing items in a group, you want to use a collection class and not an array.

When you define an array’s size, you need to know that they are zero-based arrays. That is, the first element in the array is item zero. Therefore, if you dimension an array as myArray(6), it contains seven items (0 through 6). Each item is contiguous and sequential. This enables you to set and access items quickly using the items index.

The typical array you create is one dimensional, meaning that it contains a single group of indexed items. You declare this type of an array by indicating the number of elements in the array either on the declaration of the variable or before the array’s first use. There are a few valid syntaxes for defining an array. The standard way in C# is to use the new keyword to set the size of the array. In VB, you can set the size of the array without using the keyword new. The following shows an example:

C#
short[] salesRegionCodes = new short[numRegions];

VB

Dim salesRegionCodes(numRegions) As Short

You access an array through its index value. Array objects inherit for the System.Array class. This gives you a number of properties and methods you can use including getting the type of values in the array (GetType), getting the total number of elements in all dimensions of an array (Length), and getting the upper-bound value for a single dimension (GetUpperBound). The following code shows an example of using this last method and accessing an array through its index:

C#
for (int i = 0; i < salesRegionCodes.GetUpperBound(0); i++)
{
  short code = salesRegionCodes[i];
  //additional processing ...
}

VB

For i = 0 To salesRegionCodes.GetUpperBound(0)

  Dim code As Short = salesRegionCodes(i)
  'additional processing ...
Next

You can also initialize the values in an array inside the declaration statement. In this case, the number of elements you define sets the size of the array. The following is an example:

C#
double[] salesFigures = new double[] {12345.98, 236789.86, 67854.12};

VB

Dim salesFigures() As Double = {12345.98, 236789.86, 67854.12}

You can define arrays that have more than a single dimension (up to 32). A common scenario is a two-dimensional array where one dimension is considered rows and the other columns. You can use the Rank property to determine the number of dimensions in an array.

For example of a multidimensional array, consider one that contains sales figures for each sales representative (rows) in each region (columns). You might define this array as follows:

C#
double[,] salesByRegion = new double[6, 5];

VB

Dim salesByRegion(6, 5) As Double

Note that an array can also contain other arrays. These type of arrays are called jagged arrays (or arrays of arrays). They are considered jagged because each element in the array might contain an array of different size and dimension; therefore, there might be no real uniformity to the array.

Collection Classes and Generics

A collection class can give you more flexibility when working with objects. For example you can have objects of different types in a single collection; collections can be of varying lengths; you can easily add and remove items in a collection.

The standard collection classes are defined inside the System.Collections namespace. The classes in this namespace include a base class for creating your own, custom collections (CollectionBase), and more specific collections such as ArrayList, Stack, SortedList, Queue, and HashTable.

For example, you might create a simple, dynamic ArrayList to contain a set of sales figures. The following code shows how you can create a new ArrayList, add items to it, and loop through those items:

C#
ArrayList salesFigures = new ArrayList();

salesFigures.Add(12345.67);
salesFigures.Add(3424.97);
salesFigures.Add("None");

for (int i = 0; i < salesFigures.Count; i++)
{
  object figure = salesFigures[i];
  //process figures ...
}

VB

Dim salesFigures As New ArrayList()

salesFigures.Add(12345.67)
salesFigures.Add(3424.97)
salesFigures.Add("None")

For i As Integer = 0 To salesFigures.Count - 1
 Dim figure As Object = salesFigures(i)
 'process sales figure data ...
Next

Of course, many additional properties and methods are available to you through the ArrayList and related collection classes. You should explore these for your specific scenarios.

Notice in the preceding code that the collection class has two types of objects inside it: double and string. This can be problematic if you need to rely on a collection of objects all being of the same type. For example, you might want all your sales figures to be of type double; or you might want a collection of only Employee objects. In these cases, you need a strongly typed collection class. You can create these by coding your own, custom collection classes (inheriting from CollectionBase and implementing the interfaces specific to your needs). However, .NET also provides a set of classes called generics that allow for strongly typed groups of objects.

Generic collections can be found inside the System.Collections.Generic namespace. A generic collection class enables you to define the type that the class contains when you initialize it. This then restricts what types the class can contain. You can rely on this information within your code.

You define a generic list in C# using angle brackets (<>) with the type defined inside those brackets. In VB, you define the generic type inside parenthesis using the Of keyword. For example, the following defines a simple, generic list of items that can only include values of type double:

C#
List<double> salesFigures = new List<double>();

VB

Dim salesFigures As New List(Of Double)

There are many generic collection classes available to you, including Dictionary, HashSet, LinkedList, List, Queue, SortedList, Stack, and more. You can also write your own generic collection classes.

Tuples

The System.Tuple class enables you to create a set, ordered list of items and work with that list. After you’ve created the list, the list cannot be changed. This makes for easy storage (and access) of sequential items.

For example, if you wanted to create a Tuple to store the month names in the first quarter you could do so using the static member Tuple.Create. Each item you want to add to the list you add inside parentheses (and separated by commas). You can then access the items in your Tuple using the Item1, Item2, Item3 syntax. Note that the Tuple only exposes item properties for the number of items that exist inside the group. The following code shows an example:

C#
var q1Months = Tuple.Create("Jan", "Feb", "Mar");
string month1 = q1Months.Item1;

VB

Dim q1Months = Tuple.Create("Jan", "Feb", "Mar")
Dim month1 As String = q1Months.Item1

The Tuple class is based on generics. You define the type of object you enable for each member in the list. The Create method shown infers this type for you. However, you might want to be explicit. In this case, you can declare your types using the constructor as follows:

C#
Tuple<int, string, int, string, int, string> q1MonthNumAndName =
        Tuple.Create(1, "Jan", 2, "Feb", 3, "Mar");

VB

Dim q1MonthNumAndName As Tuple(Of Integer, String, Integer, String,
                               Integer, String) =
  Tuple.Create(1, "Jan", 2, "Feb", 3, "Mar")

Programming with Attributes

Sometimes you need to provide metadata about the capabilities of your code. This metadata is meant to tell other code that is inspecting your code (through reflection) specific things about what the code might do. This includes information for the .NET runtime such as how you want your code compiled. There are many attributes available in the .NET Framework. You can also create your own, custom attributes to be applied to your code. In this case, you can write code to examine the metadata about your own application.

Declarative attributes can be applied to classes, properties, methods, parameters, and other elements inside your code. You can apply a single attribute or multiple attributes to an application. Some attributes also might take parameters to indicate additional information to the attribute code.

Note that by convention all attributes end with the word Attribute in their names, such as SerializableAttribute. You typically leave the word attribute off your declaration, however, as it is not required.

In C#, attributes are placed on code using square brackets ([]). For example, you can use the ConditionalAttribute to indicate to the compiler which code should be compiled based on environment variables or command-line options. You would apply this attribute to your code as shown:

C#
[System.Diagnostics.Conditional("DEBUG")]
public void EmployeeCalculationsTestMethod()
{
  //code that compiles in the debug version of the assembly
}

In VB, you decorate your code elements with an attribute by putting the attribute in angle brackets (<>) in front of the code element, as follows:

VB

<Conditional("DEBUG")> Public Sub EmployeeCalculationsTestMethod()
  'code that compiles in the debug version of the assembly
End Sub

Exception Handling

A lot of programming time is spent eliminating exceptions from our code. However, you can’t always eliminate all scenarios that might cause an exception. In these cases, you need a way to anticipate the exception and then, if possible, handle the exception in your code. There is where the Try...Catch...Finally construct comes into play.

You put a Try statement around a block of code you expect might cause an exception. You typically do so if you intend to handle the error. If you are not intending to handle the error, you can let the error bubble up to the calling code. Of course, you need to have an outer-error handler (or manager) inside your outer code to prevent errors from bubbling up to users in nasty ways.

When an exception actually occurs inside your Try block, execution is immediately passed to a Catch block. This might be a general catch of all errors or a catch meant for a specific exception type. The code inside the catch block is then meant to handle the error. Handling an error might include logging the error, sending it to a message system, or actually trying something different (or trying again using a jump statement) as the result of the error.

The following shows a basic example. Inside the Try block is a calculation that does division. This Try block has the possibility of raising an exception in the case where the division is done by zero. This condition raises the specific exception DivideByZeroException. There is a Catch block that consumes this (and only this) type of exception. You can add code to the Catch block to either eat the exception (do nothing) or process it somehow. Also, if you want to rethrow the exception after handling it, you can do that, too:

C#
try
{
  averageSales = salesToDate / avgRate;
}
catch (System.DivideByZeroException e)
{
  //handle the exception ...
  // if re-throwing use: throw e;
}

VB

Try
  averageSales = salesToDate / avgRate

Catch ex As System.DivideByZeroException
  'handle the exception ...
  ' if re-throwing use: Throw ex
End Try

You can have multiple Catch blocks be both specific and generic. Note that if no exception type is found in a Catch block, the exception is actually not handled but gets bubbled up to the calling code (or to the runtime).

Note that you can also rethrow the error from your Catch block using the Throw keyword. If you do not rethrow the exception, the runtime assumes you have handled the error and moves on. You can also use throw anywhere in your application where you want to raise an exception.

There is also a Finally block that you can write. This bit of code goes after your Catch blocks. It runs regardless of whether an exception is raised. It is useful for cleaning up any resources that might have been allocated inside the Try block.

Creating and Raising Events

There is not much functionality you can build using the .NET languages without events. Events enable one piece of code to notify another bit of code that something has just happened. Code that raises events are said to publish an event and those that receive the event notice are said to subscribe to events. A simple example is when you write a user interface for the Web or Windows. In these cases, you are consistently adding code that subscribes to events published by the UI such as a user clicking a button control. Of course, an event may have more than a single subscriber and subscribers may be subscribed to multiple events.

Create an Event

When you create an event you need to determine whether you need to pass custom data to the subscribers. This custom data is referred to as event arguments (or args). If you do not need to pass custom data, you simply declare the event using the keyword event and the existing delegate EventHandler. For example, if you were to define a simple event that you would raise when an employee class is updated, you might define that event as follows:

C#
public event EventHandler RaiseEmployeeUpdatedEvent;

VB

Public Event RaiseEmployeeUpdatedEvent As EventHandler

By declaring the event, you have effectively published it. Subscribers that have a reference to your class can then set up a subscription to your event. You then need to raise the event in the same class where you published it. This notifies the subscribers that the event has fired.

It is slightly more complicated to define events where you need to pass custom data. In this case, you must first create a custom class to maintain your event data. This class must inherit from the EventArgs base class. For example, you might create a custom event arguments class to contain the employee ID for the employee-updated event. In this case, your custom class contains a property to hold the Id value and a constructor for passing in this value, as in the following code:

C#
public class EmployeeUpdatedEventArgs : EventArgs
{
  public EmployeeUpdatedEventArgs(string id)
  {
    _id = id;
  }

  private string _id;
  public string EmployeeId
  {
    get { return _id; }
  }
}

VB

Public Class EmployeeUpdatedEventArgs
  Inherits EventArgs

  Public Sub New(ByVal id As String)
    _id = id
  End Sub

  Private _id As String
  Public ReadOnly Property EmployeeId() As String
    Get
      Return _id
    End Get
  End Property

End Class

When you use a custom event argument, you need to declare your event to use the custom event argument class. You can do so using the version of the EventHandler class that is defined as a generic. In this case, you indicate the class that contains the argument as part of the generic definition of EventHandler. This class also automatically contains the sender argument (typically a copy of the object publishing the event). The following shows an example of defining this custom event handler:

C#
public event EventHandler<EmployeeUpdatedEventArgs> RaiseEmployeeUpdatedCustomEvent;

VB

Public Event RaiseEmployeeUpdatedCustomEvent As _
  EventHandler(Of EmployeeUpdatedEventArgs)

Raise an Event

You raise the event in the same class where the event is defined. An event is raised as the result of some action. In the case of the example, the action is the employee class has been updated. To raise the event, you simply call it in the right spot and pass the appropriate parameters. In the case of the employee-updated custom event, you pass an instance of the employee class as the sender and then the employee Id as part of an instance of the EmployeeUpdatedEventArgs, as shown here:

C#
public void UpdateEmployee()
{
  //do work to update employee ...

  //raise event to notify subscribers of the update
  RaiseEmployeeUpdatedCustomEvent(this, new EmployeeUpdatedEventArgs(this.Id));
}

VB

Public Sub UpdateEmployee()
  'do work to update employee ...

  'raise event to notify subscribers of update
  RaiseEvent RaiseEmployeeUpdatedCustomEvent(Me, _
    New EmployeeUpdatedEventArgs(Me.Id))
End Sub

Subscribe to and Handle an Event

The final step is to actually listen for (or subscribe to) the event. Here, you need to do two things. First, you must write a method that mimics the signature of the event. The content of this method is yours to write. It is called when the event fires. The following shows an example of a method (inside a class that subscribes to the employee class) that gets called when the event fires. Notice how this method uses the custom event type and must therefore match that signature:

C#
private void OnEmployeeUpdate(object sender, EmployeeUpdatedEventArgs e)
{
  //do something in response to employee update
  string empId = e.EmployeeId;
}

VB

Private Sub OnEmployeeUpdate(ByVal sender As Object, _
  ByVal e As EmployeeUpdatedEventArgs)

  Dim empId As String = e.EmployeeId
  Console.WriteLine("Event Fired: id=" & empId)
End Sub

Second, you must register your event handler with the actual event. This is done by adding a pointer to the event using the += (C#) or AddHandler (VB) syntax. You typically add your handlers inside the subscribing class’s constructor or initialization code. The following shows code to connect the OnEmployeeUpdate handler to the RaiseEmployeeUpdatedCustomEvent event:

C#
Employee _emp = new Employee();
_emp.RaiseEmployeeUpdatedCustomEvent += this.OnEmployeeUpdate;

VB

AddHandler _emp.RaiseEmployeeUpdatedCustomEvent, AddressOf OnEmployeeUpdate

When the code is run, you undoubtedly access features of the class that fire the event (in this case, Employee.UpdateEmployee). When you hit a method that triggers the event, your subscribing code is called accordingly.

  • + Share This
  • 🔖 Save To Your Account

Discussions

comments powered by Disqus