Chapter 4
Learning Just Enough C# and VB.NET: Intermediate Syntax

Key Skills & Concepts

Image Use Delegates and Events

Image Implement Interfaces

Image Code with Arrays and Generics

In previous chapters, you learned basic syntax and how to create your own types. This chapter rounds out the bare essentials of what you need to know with delegates and events, interfaces, and a quick introduction to arrays and generics. This material doesn’t attempt to be too advanced, but gives you enough information to understand the language concepts involved. You’ll see all of these language features being used throughout the book, and it’s good to have some background on what they mean. Let’s start off with delegates and events.

Understanding Delegates and Events

Sometimes you need to write flexible code that performs general operations. For example, when the designers of the .NET Framework created user interfaces, they added reusable controls, such as buttons, list boxes, and grids. When writing these controls, the framework designers didn’t know how we would use them. For example, how would anyone know what we wanted our code to do when a user clicks a button on the user interface? So, these controls have interaction points built in so that they can communicate with your program; these interaction points are called events. These events fire whenever a user performs an action such as a button click or a list box selection. We write code to hook up these events to some other code in our program that we want to run when that event happens, such as when the user clicks a button, and this is what delegates are used for.

An event defines the type of notifications that a object can provide, and a delegate allows us to connect the event to the code we want to run.

This section will show you the mechanics of how delegates and events work, but you should understand that the mechanics may seem somewhat abstract at first. Delegates and events are most often used when you’re working with .NET Framework technologies that use them, such as Windows Presentation Foundation (WPF), Silverlight, and ASP.NET. What you’ll want to do is get a feel for the mechanics right now and then refer back to this discussion when you encounter delegates and events in later chapters.

The next section will add more logic to the set accessor in CurrentBalance in the next listing and raise an event for the calling code.

Events

An event is a type of class member that allows your class or class instance to notify any other code about things that happen within that class. To help you understand the use of events, this section will associate an event with the accountBalance of an account. Listing 4-1 is a modified version of Listing 3-8 from Chapter 3. It additionally has an event and logic that raises the event.

To see how an event can be useful, consider a program that uses a class that manages accounts. There could be different types of accounts, such as checking or savings. If a customer performs an overdraft, the consequences probably vary by what type of account is being used. However, all you want is a generalized account class that can be used by any bank account type and doesn’t know what the overdraft rules are, which makes the class more reusable in different scenarios. Therefore, you can give the account class an event that will fire off a notification whenever an overdraft occurs. Then, within your specialized checking account class instance, for example, you can register something called an event handler so that the instance of the class knows each time the overdraft event occurs via the handler.

In Listing 4-1, the CurrentBalance property is modified to raise (or fire off) an OverDraft event whenever the assigned value is less than 0. The Main method hooks up another method that will run whenever that event occurs. I’ll explain the event first and then follow up with a discussion of how to hook up a method that listens for when the event is raised and receives the message sent by the event.

Listing 4-1 Event demo

C#:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace FirstProgram
{
    class Program
    {
        private decimal accountBalance = 100m;

        static void Main(string[] args)
    {
        Program account = new Program();
        account.OverDraft += new EventHandler(account_OverDraft);
        account.CurrentBalance = -1;

        Console.ReadKey();
    }

    public decimal CurrentBalance
    {
        get
        {
            return accountBalance;
        }
        set
        {
            if   (value < 0)
            {
                  if   (OverDraft  != null)
                  {
                        OverDraft(this, EventArgs.Empty);
                  }
            }
            accountBalance = value;
        }
    }
    static void account_OverDraft(object sender,  EventArgs e)
    {
        Console.WriteLine("Overdraft Occurred");
    }
    public event EventHandler OverDraft;
  }
}

VB:

Module Module1
    Private Dim accountBalance As Decimal = 100

    Sub Main()
        AddHandler OverDraft, AddressOf AccountOverdraft
        CurrentBalance = -1
        Console.ReadKey()
     End Sub

     Public Event OverDraft As EventHandler

     Public Sub AccountOverdraft (ByVal sender As Object, ByVal e As
EventArgs)
         Console.WriteLine("Overdraft Occurred")
     End Sub
End Module

Listing 4-1 has an event named OverDraft. The OverDraft event is public and is declared with the event keyword. The EventHandler is a delegate, which we’ll discuss soon, but it basically allows you to define the type of method that can be called by the event. It defines the communication contract that must be adhered to by any code that wishes to listen for the event to fire.

Look at the set accessor of the CurrentBalance property, inside of the if statement where it determines if value is less than 0. The C# example has another if statement to see if the OverDraft event is equal to null.

In C# when an event is equal to null, it means that nothing has subscribed to be notified by the event—in essence, no other code is listening. However, when the C# event is not null, then this indicates that some code somewhere has hooked up a method to be called when the event fires. That method is said to be listening for the event. So, assuming that the caller has hooked up a method, the OverDraft event is fired. This check for null is important. If nothing is listening for the event (and our code knows this to be the case when the event is null), and we raise or fire the event by calling OverDraft(this, EventArgs.Empty), an error (null reference exception) would occur at runtime whenever a value is set into the CurrentBalance property. The arguments to the C# event mean that the current object (which is the Program class instance), this, and an empty EventArgs will be passed as the event message to any other methods that were hooked up to this event. It is interesting to note that many methods can be hooked up to your event (or none at all), and each will be notified in turn when your event fires. You should start to see that events really are a form of almost spontaneous communication within your program.

In VB, you don’t need to check for Nothing (equivalent to C# null).

The preceding discussion talked about a method that is hooked up to the event and executes (receives a message) whenever the event fires. The next section explains how to use a delegate to specify what this method is.

Delegates

Delegates let you hook up methods as the receiver to specific events. The delegate specifies the allowable signature, the number of arguments, and their types, of a method that is allowed to be hooked up to the event as a listener or handler. The EventHandler delegate type for the OverDraft event specifies what the signature of a method should be, as follows:

C#:

public event EventHandler OverDraft;

VB:

Public Event OverDraft As EventHandler

This EventHandler is a class that belongs to the .NET Framework class library, and it, by definition, specifies that any methods hooked up to the OverDraft event must define two parameters: an object of any type and an EventArgs class. EventHandler also specifies that the method does not return a value explicitly. The following method, account_ OverDraft (AccountOverdraft in VB), matches the predefined EventHandler signature:

C#:

static void account_OverDraft(object sender,  EventArgs e)
{
    Console.WriteLine("Overdraft Occurred");
}

VB:

Public Sub AccountOverdraft(ByVal sender As Object,  ByVal e As
EventArgs)
     Console.WriteLine("Overdraft Occurred")
End Sub

Notice that the C# account_OverDraft (AccountOverdraft in VB) doesn’t return a value and has two parameters that are type object and EventArgs, respectively. The account_OverDraft (AccountOverdraft in VB) method is hooked up to the OverDraft event in the Main method in Listing 4-1, repeated as follows for your convenience:

C#:

account.OverDraft += new EventHandler(account_OverDraft);
account.CurrentBalance = -1;

VB:

AddHandler OverDraft, AddressOf AccountOverdraft
CurrentBalance = -1

In the C# example, the += syntax is for assigning a delegate to an event (using a bit of programmer slang, this syntax is commonly said to "wire up an event"). The VB example uses AddHandler and AddressOf to assign the AccountOverDraft method to the OverDraft event. In the C# example, the delegate is a new instance of EventHandler and the event is OverDraft. If you remember, the delegate type of OverDraft is Eventhandler, which defines the precise message contract.

The next piece of the puzzle is the method to be notified when the event happens. This method is the parameter given to the new EventHandler delegate instance. You saw earlier where the account_OverDraft (AccountOverDraft in VB) method had the signature specified by the EventHandler class, making it possible for our method to be specified as the new EventHandler parameter. With that one line of code (the one with the += statement), account_OverDraft (AccountOverdraft in VB) is now hooked up to the OverDraft event. This means that when the value of CurrentBalance is set to less than zero via the set accessor of CurrentBalance, the OverDraft event gets fired because the OverDraft(this, EventArgs.Empty) is called, which then invokes the account_OverDraft (AccountOverdraft in VB) method (the method we wired up to the event), which in turn executes its code.

One more note about events: you’ll see them used extensively in graphical user interface (GUI) code. Think about the GUI code that has reusable components, like buttons and list boxes. Every time the user clicks a button or selects an item in the list box, you want code to execute and do something, like perhaps save the user’s data somewhere. You do this through events: a Click event for the button and a SelectedItemChanged for the list box. This is the standard way that you program GUIs; you have an event and you define a method to hook up to that event so that your running program can do some work in reaction to the user.

Event, Delegate, and Handler Code Completion

While there isn’t a snippet, per se, to create an event or delegate, in C# there is Intellisense Code Completion support for hooking a delegate up to an event, which also generates the handler method. The process takes two steps: delegate and handler creation. To get started, type the reference to the event’s containing instance, the event name, and +=. As soon as you type the = sign, you’ll see a tooltip like the one in Figure 4-1.

Image

Figure 4-1 Code completion for delegate assignment

Image

Figure 4-2 Code completion for handler method creation

As you can see, the Editor pops up a tooltip instructing you to type TAB to create a new delegate instance. Type TAB and Code Completion will pop up another tooltip for creating the handler method, as shown in Figure 4-2.

In Figure 4-2, you can see that Code Completion is suggesting a method name for you. You have a choice of pressing TAB or changing the method name and then pressing TAB. Either way, you have a fast way to hook up a handler method to an event via the event’s delegate type.

Just as a delegate provides an interface to a method that is a contract basically to describe how to communicate, you can also define interfaces to classes to communicate with them in a specified way, and these are intuitively named … interfaces.

Implementing Interfaces

Another language feature that gives you flexibility is interfaces. An interface can be useful if you want to have a group of classes that can be interchanged at any time, yet you need to write the same operations for each of these classes. Essentially, you want to write the code that uses the class only one time, but still switch what the actual class is. That’s where interfaces come in. The interface creates a contract that each of the interchangeable classes must adhere to. So, if the interface says that all classes that implement the interface have method A and property B, then every class that implements the interface must have method A and property B; the compiler enforces this like a contract that cannot be broken. The following sections show you how to write an interface and then build a couple of classes that implement that interface. Finally, you’ll see how to write code against the interface.

One important fact to remember about interfaces is that they don’t have any code other than definitions of members. This definition of members is the contract of the interface. You are the one who must to write a class that contains the members of the interface, and you must write the code that provides an implementation of the interface members. A common point of confusion is that an interface does not have any executable code, but the classes that implement the interfaces do.

The following sections show you how to create an interface, how to create a class that has code (that you’ve written) to implement the interface contract, and how to write code that operates on the classes that implement (guarantee the contract of) the interface.

Creating an Interface

To create an interface, right-click the project in Solution Explorer, select Add | New Item, select Code under the language branch in Installed Templates, and select the Interface item. Name the Interface IAccount and click Add. By standard convention, you will always name any interface class you create with a name that starts with an uppercase letter I. You’ll see the interface in Listing 4-2 added to your project:

Listing 4-2 An interface

C#:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace FirstProgram
{

    public interface IAccount
    {

       void Credit(decimal amount);
       void Debit(decimal amount);
       decimal CurrentBalance  { get;   set; }
    }
}

VB:

Public Interface IAccount
    Sub Credit(ByVal amount As Decimal)
    Sub Debit(ByVal amount As Decimal)
    Property CurrentBalance As Decimal
End Interface

After you’ve added the interface, you’ll need to make modifications to make the code match Listing 4-2. Notice that the IAccount members don’t have an implementation and so appear incomplete because they have no lines of code. Also, each member doesn’t have a public modifier, because interface members are implicitly public. The following sections show you how to build the classes that implement the IAccount interface; there, you should begin to see the benefit that an interface can bring.

Making Classes Implement the Interface

To create a class, right-click the project in Solution Explorer, select Add | New Item, select Code under the language branch in Installed Templates, and select the Class item. Name the class Checking and click Add. Using the same procedure as Checking, add another class, but name it Saving. Listings 4-3 and 4-4 show the two new classes.

Listing 4-3 Checking class that implements | Account interface

C#:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace FirstProgram
{

    class Checking  : IAccount
    {
        public void Credit(decimal amount)
        {
             // implement checking logic
             CurrentBalance += amount;
             Console.Writeline("Added " + amount.ToString() +
                                      " to Checking Account");
        }

        public void Debit(decimal amount)
        {
            // implement checking logic
            CurrentBalance -= amount;
            Console.Writeline("Debited " + amount.ToString() +
                                       "  from Checking Account");
        }

        public decimal CurrentBalance  { get;   set; }
    }
}

VB:

Public Class Checking
    Implements IAccount

    Public Sub Credit(ByVal amount As Decimal)   Implements IAccount.
Credit
    '   Implement Checking logic
    CurrentBalance += amount
        Console.Writeline("Added "  & amount.ToString() &
                          " to Checking Account")

End Sub

Public Sub Debit(ByVal amount As Decimal)   Implements IAccount.Debit
    '   Implement Checking logic
    CurrentBalance -= amount
        Console.Writeline("Debited " + amount.ToString() +
                          "  from Checking Account")
End Sub

    Public Property CurrentBalance As Decimal Implements IAccount.
CurrentBalance
End Class

Listing 4-4 Saving class that implements IAccount interface

C#:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace FirstProgram
{
    class Saving  : IAccount
    {

        public void Credit(decimal amount)
        {
            // implement savings logic
            CurrentBalance += amount;
            Console.Writeline("Added " + amount.ToString() +
                              " to Saving Account");
        }

        public void Debit(decimal amount)
        {
           // implement savings logic
           CurrentBalance -= amount;
           Console.Writeline("Debited " + amount.ToString() +
                             "  from Saving Account");
        }
           public decimal CurrentBalance  { get;   set; }
     }
}

VB:

Public Class Saving
    Implements IAccount

    Public Sub Credit(ByVal amount As Decimal)   Implements IAccount.
Credit
       ' Implement Saving logic
       CurrentBalance += amount
            Console.Writeline("Added "  & amount.ToString() &
                              " to Saving Account")
    End Sub

    Public Sub Debit(ByVal amount As Decimal)   Implements IAccount.Debit
        '   Implement Saving logic
        CurrentBalance -= amount
            Console.Writeline("Debited " + amount.ToString() +
                              "  from Saving Account")
  End Sub

  Public Property CurrentBalance As Decimal
      Implements IAccount.CurrentBalance
End Class

In both Listings 4-3 and 4-4, notice that the Checking and Saving, respectively, implement the IAccount interface, repeated as follows:

C#:

class Checking  : IAccount

and

class Saving  : IAccount

VB:

Public Class Checking
    Implements IAccount

and

Public Class Saving
    Implements IAccount

In the C# listing, following the class name by a colon and then the interface name specifies that the class will implement the interface. The VB listing uses the Implements keyword to indicate that Checking and Saving classes implement the IAccount interface. Looking at both Checking and Saving, you can see that they have the Credit, Debit, and CurrentBalance members that are specified in IAccount. The primary difference is that IAccount doesn’t have an implementation, but you wrote an implementation for Checking and Saving. Listings 4-3 and 4-4 simplify the implementation of the interface so that you don’t have to read a lot of code that doesn’t add to the purpose of the listing to show you how a class implements an interface. In reality, the code in the methods would be different for Checking and Saving because they are different account types with different business rules.

You’ve created an interface and written classes to implement the contract of that interface. The next section gives you a couple of examples to help clarify the practical use of interfaces.

Writing Code That Uses an Interface

One of the best ways to understand the value of interfaces is to see a problem that interfaces solve. In this section, I’ll show you some code that accesses the Checking and Saving classes individually, essentially duplicating code. Then I’ll show you how to write the code a single time with interfaces. The particular example runs a payroll by obtaining instances of Checking and Saving classes and crediting each class, which is synonymous with employees being paid. Starting with the bad example, Listing 4-5 shows how this code works.

Listing 4-5 Processing payroll with explicit checking and saving class instances

C#:

public void ProcessPayrollForCheckingAndSavingAccounts()
{
    Checking[]   checkAccounts = GetCheckingAccounts();

    foreach  (var checkAcct in checkAccounts)
    {
        checkAcct.Credit(500);
    }
    Saving[]   savingAccounts = GetSavingAccounts();

    foreach  (var savingAcct in savingAccounts)
    {
       savingAcct.Credit(500);
    }
}

public Checking[] GetCheckingAccounts()
{

    Checking[]   chkAccts = new Checking[2];

    chkAccts[0] = new Checking();
    chkAccts[1]   = new Checking();

    return chkAccts;
}

public Saving[] GetSavingAccounts()
{

    int numberOfAccounts = 5;
    Saving[]   savAccts = new Saving[numberOfAccounts];

    for  (int i = 0;  i < numberOfAccounts; i + +)
    {
          savAccts[i]   = new Saving();
    }

    return savAccts;
}

VB:

Sub ProcessPayrollForCheckingAndSavingAccounts()
    Dim checkAccounts As Checking()   = GetCheckingAccounts()

    For Each checkAcct In checkAccounts
        checkAcct.Credit(500)
    Next

    Dim savingAccounts As Saving()   = GetSavingsAccounts()

    For Each savingAcct In savingAccounts
        savingAcct.Credit(500)

    Next
End Sub

Function GetCheckingAccounts()  As Checking()
    Dim chkAccts(1)  As Checking

    chkAccts(0) = New Checking()
    chkAccts(1)  = New Checking()

    Return chkAccts
End Function

Function GetSavingsAccounts()  As Saving()
    Dim numberOfAccounts As Integer = 5
    Dim savAccts(numberOfAccounts)  As Saving

    For i As Integer = 0 To numberOfAccounts
        savAccts(i)   = New Saving()
    Next

    Return savAccts
End Function

To save space, I haven’t included the entire application in Listing 4-5, which is available with the source code for this book via the McGraw-Hill Web site. To understand how it works, imagine that you’ve written the following code in the Main method:

C#:

Program bank = new Program();
bank.ProcessPayrollForCheckingAndSavingAccounts();

VB:

ProcessPayrollForCheckingAndSavingAccounts()

Walking through the code, let’s start at the ProcessPayrollForCheckingAndSaving Accounts method. You can see how the algorithm calls GetCheckingAccounts to retrieve an array of Checking objects. If you recall, an array is a list of elements of a specified type, that type being Checking in this case. The algorithm goes on to iterate through the Checking objects, invoking Credit on each to add 500 to the account. Some employees want their paychecks in Checking, but others might want their paychecks to go into Saving (or some other account). Therefore, the algorithm calls GetSavingsAccounts to get a list of those accounts for employees who want their paychecks to go into their savings. You’ll notice that the algorithm inside of GetSavingsAccounts is different from GetCheckingAccounts, which I did on purpose so that you’ll see different ways to use loops; but this doesn’t affect the calling code because it’s encapsulated in individual methods. The point to make here is that GetCheckingAccounts will only return Checking class instances and GetSavingsAccounts will only return Saving class instances. The rest of the algorithm in the ProcessPayrollForCheckingAndSavingAccounts method mirrors the processing for Checking.

What should catch your attention is the duplication of code in the ProcessPayroll ForCheckingAndSavingAccounts method. Although the Credit methods of Checking and Saving should have different implementations, the code calling Credit can be the same, eliminating duplication. Listing 4-6 shows how to take advantage of the fact that both Checking and Saving implement the same interface, IAccount. You’ll see how to call Credit on any IAccount-derived type with one algorithm, eliminating the duplication you saw in Listing 4-5.

Listing 4-6 Processing payroll through the IAccount interface

C#:

public void ProcessPayrollForAllAccounts()
{

    IAccount[]   accounts = GetAllAccounts();

    foreach  (var account in accounts)
    {
        account.Credit(1000);
    }
}

public IAccount[] GetAllAccounts()
{

    IAccount[]   allAccounts = new IAccount[4];

    allAccounts[0] = new Checking();
    allAccounts[1] = new Saving();
    allAccounts[2] = new Checking();
    allAccounts[3] = new Saving();

    return allAccounts;
}

VB:

Sub ProcessPayrollForAllAccounts()
    Dim accounts As IAccount()   = GetAllAccounts()

    For Each account In accounts
        account.Credit(1000)

    Next
End Sub

Function GetAllAccounts()  As IAccount()
    Dim allAccounts(3)  As IAccount

    allAccounts(0) = New Checking()
    allAccounts(1) = New Saving()
    allAccounts(2) = New Checking()
    allAccounts(3) = New Saving()

    Return allAccounts
End Function

You can call the code in Listing 4-6 from the Main method like this:

C#:

Program bank = new Program();
bank.ProcessPayrollForAllAccounts();

VB:

ProcessPayrollForAllAccounts()

Examining Listing 4-6, you can see that accounts is an array of IAccount. While you can’t instantiate an interface by itself, you can assign an instance of the class that implements that interface using a variable simply declared as the interface type. In this case, GetAllAccounts returns a list of objects that implement IAccount.

Looking inside of the GetAllAccounts method, you can see how an array is being built with both Checking and Saving objects. Since Checking and Saving implement IAccount, which you saw in Listings 4-3 and 4-4, instances of Checking and Saving can be directly assigned into elements of an IAccount array.

Back in the ProcessPayrollForAllAccounts method, you can see a loop iterate through each IAccount instance, calling Credit. The reason you can call Credit like this is that IAccount defines a contract for the Credit method. Calling Credit on each instance really

Image

Figure 4-3 The C# interface snippet template

invokes the Credit method on the runtime Checking or Saving instance. Your code that you wrote for Checking.Credit and Saving.Credit will execute as if your code called them directly as in Listing 4-5. Also observe that we’ve eliminated the duplication because one algorithm, namely IAccount.Credit() in our example, works on both Checking and Saving objects.

Now you can see that interfaces help you treat different types of objects as if they were the same type and helps you simplify the code you need to write when interacting with those objects, eliminating duplication. Imagine what would happen if you were tasked with adding more bank account types to this algorithm without interfaces; you would need to go into the algorithm to write duplicate code for each account type. However, now you can create the new account types and derive them from IAccount; the new account types automatically work in the same algorithm.

The interface Snippet

Before using the interface snippet, open a new file by right-clicking your project in VS Solution Explorer, select Add | New Item | Code File, and name the file IInvestment.cs(or IInvestment.vb in VB). You’ll have a blank file to work with. To use the interface snippet, type int and press TAB, TAB; you’ll see a snippet template similar to Figure 4-3 (C#) or Figure 4-4 (VB).

Because prefixing interfaces with I is an expected convention, the template highlights the identifier after I.

Image

Figure 4-4 The VB interface snippet template

Applying Arrays and Generics

Whatever code you write will typically need to group objects into a single collection of that object type. For this, you can use an array, which is a container that can have zero or many elements, each holding an instance of a particular type. You’ll soon see how to use an array to locate the elements (items) you want. There are also generic collection classes in the .NET Framework that are even more powerful than arrays. You’ll learn how to use both arrays and generic collections in this section.

Coding Arrays

You’ve already seen several examples of arrays being used previously in this chapter. You declare a variable of the array type, instantiate the array to a specified size, and then use the array by indexing into its elements. Listing 4-7 shows an example that demonstrates the mechanics of creating and using an array.

Listing 4-7 Creating and using an array

C#:

private void ArrayDemo()
{
    double[]   stats = new double[3];

    stats[0] = 1.1;
    stats[1] = 2.2;
    stats[2] = 3.3;

    double sum = 0;

    for (int i = 0; i < stats.Length; i++)
    {
         sum += stats[i];
    }

    Console.WriteLine(
        stats[0] + " + " +
        stats[1] + " + " +
        stats[2] + " = " +
        sum);
}

VB:

Sub ArrayDemo()
    Dim stats(2)  As Double

    stats(0) = 1.1
    stats(1) = 2.2
    stats(2) = 3.3

    Dim sum As Double = 0


    For i As Integer = 0 To 2
        sum += stats(i)
    Next

    Console.WriteLine(
        stats(0) & " + " &
        stats(1) & " + " &
        stats(2) & " = " &
        sum)
End Sub

In the C# example of Listing 4-7, you can see that the stats variable is declared as double[], an array of type double. You must instantiate arrays, as is done by assigning new double[3] to stats, where 3 is the number of elements in the array. C# arrays are accessed via a 0-based index, meaning that stats has three elements with indexes 0, 1, and 2.

The VB example declares stats as an array of type double. Notice that the rank of the array is 2, meaning that 2 is the highest index in the array. Since the array is 0-based, stats contains indexes 0, 1, and 2; three elements total.

Assigning values to an array means that you use the name of the array and specify the index of the element you want to assign a value to. For example, stats[0] (stats(0) in VB) is the first element of the stats array, and you can see from the listing how each element of the stats array is assigned the values 1.1, 2.2, and 3.3. The for loop adds each element of the array to the sum variable. Finally, you can see how to read values from an array by examining the argument to the Console.WriteLine statement. Using the element access syntax, you can see how to read a specific element from the stats array.

An array is a fixed-size collection, and therefore somewhat limited in functionality. In practice, you’ll want to use more sophisticated collections, like the List class, which is referred to as a generic collection. Not all collection classes in the .NET Framework are generic collections; however, generic collections are now the preferred kind of collection to use in most cases.

Coding Generics

Generics are language features that allow you to write a piece of code that will work with multiple types efficiently. A generic class definition has a placeholder for the type you want it to represent, and you use this placeholder to declare the type you want to work with. There is an entire library of generic collections in .NET as well as generic types across the entire .NET Framework Class library. Because of the volume of information required for comprehensive coverage of generics, this section will only serve as a brief introduction, giving you an example of generic use that you’re most likely to see in the future. Listing 4-8 demonstrates how to declare a generic List. The code specifies the type of the list as a Checking account and then proceeds to populate the generic list and perform operations on the Checking elements of the generic list. Remember to include a using directive (imports for VB) for the System.Collections.Generic namespace near the top within your file.

Listing 4-8 Coding a generic list collection

C#:

private void ListDemo() {

    List<Checking> checkAccts = new List<Checking>();

    checkAccts.Add(new Checking());
    checkAccts.Add(new Checking());

    for  (int i = 0;  i < checkAccts.Count; i++)
    {
         Console.WriteLine(checkAccts[i].CurrentBalance);
    }
}

VB:

Sub ListDemo()
    Dim checkAccts As New List(Of Checking)

    checkAccts.Add(New Checking())
    checkAccts.Add(New Checking())


    For i As Integer = 0 To checkAccts.Count - 1
         Console.WriteLine(checkAccts(i).CurrentBalance)
    Next
End Sub

In .NET, the generic List type is declared as List<T>, or List(Of T) in VB. The T is a type placeholder, where you can specify any type you want. For example, you could create a List<int> for integers or a List<string> for strings, which would be List(Of Integer) and List(Of String) in VB, respectively. In Listing 4-8, you can see that checkAccts is declared as List<Checking> (List(Of Checking) in VB). Since a list grows dynamically to accommodate any number of elements, you use the Add method to add elements to the List. Once elements are in the List, you can use element access syntax, as shown in the for loop, to access the elements one at a time. Collections such as List are convenient because they have multiple convenience methods, such as Clear, Contains, Remove, and more.

In addition to List, the System.Collections.Generic namespace has several other generic collections, such as Dictionary, Queue, and Stack. Each generic is initialized by replacing the type parameters with the types you want to work on and then by using the specialized methods of that collection. Whenever you see the type parameter syntax, you should recognize that a generic is being used and you will have an idea of what the code means and how to read it in the documentation.

Summary

What you learned in this chapter were essential skills for upcoming chapters in the rest of the book. Knowing how delegates and events work helps you with event-driven development that is common to GUI application development. Understanding interfaces directly relates to being able to build Web services, among other uses. You’ll also make regular usage of arrays and generics, and this chapter gave you the essentials to know what collections are.

Remember that this was only an introduction to C# and VB and that there is much more to learn about these languages. Of course, this book is about VS and not languages, so the next chapter is where you’ll learn to build VS projects.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.145.186.173