Home
C# Language C# Language
C# Language Contents C# Language C# Language C# Language

C# with .NET

Prev Page Next PageNext C# Language
C# Language   C# Language
C# Language Table of Contents
C# Language Back Cover
C# Language Professional C# 2009 with .NET 3.0
C# Language Introduction
C# Language Looking at What’s New in the .NET Framework 2.0
C# Language Introducing the .NET Framework 3.0
C# Language Where C# Fits In
C# Language What You Need to Write and Run C# Code
C# Language What This site Covers
C# Language Conventions
C# Language Source Code
C# Language Errata
C# Language roque-patrick.com
C# Language The C# Language
C# Language .NET Architecture
C# Language The Relationship of C# to .NET
C# Language The Common Language Runtime
C# Language A Closer Look at Intermediate Language
C# Language Assemblies
C# Language .NET Framework Classes
C# Language Namespaces
C# Language Creating .NET Applications Using C#
C# Language The Role of C# in the .NET Enterprise Architecture
C# Language Summary
C# Language C# Basics
C# Language Before We Start
C# Language Your First C# Program
C# Language Variables
C# Language Predefined Data Types
C# Language Flow Control
C# Language Enumerations
C# Language Arrays
C# Language Namespaces
C# Language The Main() Method
C# Language More on Compiling C# Files
C# Language Console I/O
C# Language Using Comments
C# Language The C# Preprocessor Directives
C# Language C# Programming Guidelines
C# Language Summary
C# Language Objects and Types
C# Language Classes and Structs
C# Language Class Members
C# Language Structs
C# Language Partial Classes
C# Language Static Classes
C# Language The Object Class
C# Language Summary
C# Language Inheritance
C# Language Implementation Inheritance
C# Language Modifiers
C# Language Interfaces
C# Language Summary
C# Language Arrays
C# Language Simple Arrays
C# Language Multidimensional Arrays
C# Language Jagged Arrays
C# Language Array Class
C# Language Array and Collection Interfaces
C# Language Enumerations
C# Language Summary
C# Language Operators and Casts
C# Language Operators
C# Language Type Safety
C# Language Comparing Objects for Equality
C# Language Operator Overloading
C# Language User-Defined Casts
C# Language Summary
C# Language Delegates and Events
C# Language Delegate Inference
C# Language Anonymous Methods
C# Language Events
C# Language Summary
C# Language Strings and Regular Expressions
C# Language System.String
C# Language Regular Expressions
C# Language Summary
C# Language Generics
C# Language Overview
C# Language Creating Generic Classes
C# Language Generic Classes’ Features
C# Language Generic Interfaces
C# Language Generic Methods
C# Language Generic Delegates
C# Language Other Generic Framework Types
C# Language Summary
C# Language Collections
C# Language Collection Interfaces and Types
C# Language Lists
C# Language Queue
C# Language Stack
C# Language Linked Lists
C# Language Sorted Lists
C# Language Dictionaries
C# Language Dictionary with Multiple Keys
C# Language Bit Arrays
C# Language Performance
C# Language Summary
C# Language Memory Management and Pointers
C# Language Memory Management under the Hood
C# Language Freeing Unmanaged Resources
C# Language Unsafe Code
C# Language Summary
C# Language Reflection
C# Language Custom Attributes
C# Language Reflection
C# Language Summary
C# Language Errors and Exceptions
C# Language Looking into Errors and Exception Handling
C# Language Summary
C# Language Visual Studio
C# Language Visual Studio 2009
C# Language Refactoring
C# Language Visual Studio 2009 for .NET Framework 3.0
C# Language Summary
C# Language Deployment
C# Language Designing for Deployment
C# Language Deployment Options
C# Language Deployment Requirements
C# Language Deploying the .NET Runtime
C# Language Simple Deployment
C# Language Installer Projects
C# Language ClickOnce
C# Language Summary
C# Language Base Class Libraries
C# Language Assemblies
C# Language What Are Assemblies?
C# Language Assembly Structure
C# Language Cross-Language Support
C# Language Global Assembly Cache
C# Language Creating Shared Assemblies
C# Language Configuration
C# Language Summary
C# Language Tracing and Events
C# Language Tracing
C# Language Event Logging
C# Language Performance Monitoring
C# Language Summary
C# Language Threading and Synchronization
C# Language Overview
C# Language Asynchronous Delegates
C# Language The Thread Class
C# Language Thread Pools
C# Language Threading Issues
C# Language Synchronization
C# Language COM Apartments
C# Language Background Worker
C# Language Summary
C# Language .NET Security
C# Language Code Access Security
C# Language Support for Security in the Framework
C# Language Managing Security Policies
C# Language Role-Based Security
C# Language Summary
C# Language Localization
C# Language Namespace System.Globalization
C# Language Resources
C# Language Localization Example Using Visual Studio
C# Language Localization with ASP.NET
C# Language A Custom Resource Reader
C# Language Creating Custom Cultures
C# Language Summary
C# Language Transactions
C# Language Overview
C# Language Database and Classes
C# Language Traditional Transactions
C# Language System.Transactions
C# Language Isolation Level
C# Language Custom Resource Managers
C# Language Transactions with Windows Vista
C# Language Summary
C# Language Windows Services
C# Language What Is a Windows Service?
C# Language Windows Services Architecture
C# Language System.ServiceProcess Namespace
C# Language Creating a Windows Service
C# Language Monitoring and Controlling the Service
C# Language Troubleshooting
C# Language Power Events
C# Language Summary
C# Language COM Interoperability
C# Language .NET and COM
C# Language Marshaling
C# Language Using a COM Component from a .NET Client
C# Language Using a .NET Component from a COM Client
C# Language Platform Invoke
C# Language Summary
C# Language Data
C# Language Manipulating Files and the Registry
C# Language Managing the File System
C# Language Moving, Copying, and Deleting Files
C# Language Reading and Writing to Files
C# Language Reading Drive Information
C# Language File Security
C# Language Reading and Writing to the Registry
C# Language Reading and Writing to Isolated Storage
C# Language Summary
C# Language Data Access with .NET
C# Language ADO.NET Overview
C# Language Using Database Connections
C# Language Commands
C# Language Fast Data Access: The Data Reader
C# Language Managing Data and Relationships: The DataSet Class
C# Language Populating a DataSet
C# Language Persisting DataSet Changes
C# Language Working with ADO.NET
C# Language Summary
C# Language Manipulating XML
C# Language XML Standards Support in .NET
C# Language Introducing the System.Xml Namespace
C# Language Using MSXML in .NET
C# Language Using System.Xml Classes
C# Language Reading and Writing Streamed XML
C# Language Using the DOM in .NET
C# Language Using XPathNavigators
C# Language XML and ADO.NET
C# Language Serializing Objects in XML
C# Language Summary
C# Language .NET Programming with SQL Server 2009
C# Language .NET Runtime Host
C# Language Microsoft.SqlServer.Server
C# Language User-Defined Types
C# Language Stored Procedures
C# Language User-Defined Functions
C# Language Triggers
C# Language XML Data Type
C# Language Summary
C# Language Presentation
C# Language Windows Forms
C# Language Creating a Windows Form Application
C# Language Control Class
C# Language Standard Controls and Components
C# Language Forms
C# Language Summary
C# Language Viewing .NET Data
C# Language The DataGridView Control
C# Language DataGridView Class Hierarchy
C# Language Data Binding
C# Language Visual Studio .NET and Data Access
C# Language Summary
C# Language Graphics with GDI+
C# Language Understanding Drawing Principles
C# Language Measuring Coordinates and Areas
C# Language A Note about Debugging
C# Language Drawing Scrollable Windows
C# Language World, Page, and Device Coordinates
C# Language Colors
C# Language The Safety Palette
C# Language Pens and Brushes
C# Language Drawing Shapes and Lines
C# Language Displaying Images
C# Language Issues When Manipulating Images
C# Language Drawing Text
C# Language Simple Text Example
C# Language Fonts and Font Families
C# Language Example: Enumerating Font Families
C# Language Editing a Text Document: The CapsEditor Sample
C# Language Printing
C# Language Summary
C# Language Windows Presentation Foundation
C# Language Overview
C# Language Shapes
C# Language Controls
C# Language Layout
C# Language Event Handling
C# Language Commands
C# Language Styles, Templates, and Resources
C# Language Styles
C# Language Animations
C# Language Data Binding
C# Language Windows Forms Integration
C# Language Summary
C# Language ASP.NET Pages
C# Language ASP.NET Introduction
C# Language ASP.NET Web Forms
C# Language ADO.NET and Data Binding
C# Language Application Configuration
C# Language Summary
C# Language ASP.NET Development
C# Language Custom Controls
C# Language Master Pages
C# Language Site Navigation
C# Language Security
C# Language Themes
C# Language Web Parts
C# Language Summary
C# Language ASP.NET AJAX
C# Language What Is Ajax?
C# Language What Is ASP.NET AJAX?
C# Language ASP.NET AJAX-Enabled Web Sites
C# Language Summary
C# Language Communication
C# Language Accessing the Internet
C# Language The WebClient Class
C# Language WebRequest and WebResponse Classes
C# Language Displaying Output as an HTML Page
C# Language Utility Classes
C# Language Lower-Level Protocols
C# Language Summary
C# Language Web Services with ASP.NET
C# Language SOAP
C# Language WSDL
C# Language Web Services
C# Language Extending the Event-siteing Example
C# Language Exchanging Data Using SOAP Headers
C# Language Summary
C# Language .NET Remoting
C# Language What Is .NET Remoting?
C# Language .NET Remoting Overview
C# Language Contexts
C# Language Remote Objects, Clients, and Servers
C# Language .NET Remoting Architecture
C# Language Miscellaneous .NET Remoting Features
C# Language Summary
C# Language Enterprise Services
C# Language Overview
C# Language Creating a Simple COM+ Application
C# Language Deployment
C# Language Component Services Explorer
C# Language Client Application
C# Language Transactions
C# Language Sample Application
C# Language Integrating WCF and Enterprise Services
C# Language Summary
C# Language Message Queuing
C# Language Overview
C# Language Message Queuing Products
C# Language Message Queuing Architecture
C# Language Message Queuing Administrative Tools
C# Language Programming Message Queuing
C# Language Course Order Application
C# Language Receiving Results
C# Language Transactional Queues
C# Language Message Queue Installation
C# Language Summary
C# Language Windows Communication Foundation
C# Language Overview
C# Language Simple Service and Client
C# Language Contracts
C# Language Service Implementation
C# Language Binding
C# Language Hosting
C# Language Clients
C# Language Duplex Communication
C# Language Summary
C# Language Windows Workflow Foundation
C# Language Activities
C# Language Custom Activities
C# Language Workflows
C# Language The Workflow Runtime
C# Language Workflow Services
C# Language Hosting Workflows
C# Language The Workflow Designer
C# Language Summary
C# Language Download Details
C# Language Directory Services
C# Language The Architecture of Active Directory
C# Language Administration Tools for Active Directory
C# Language Programming Active Directory
C# Language Searching for User Objects
C# Language DSML
C# Language Summary
C# Language Part VII: Additional Information
C# Language C#, Visual Basic, and C++/CLI
C# Language Namespaces
C# Language Defining Types
C# Language Methods
C# Language Static Members
C# Language Arrays
C# Language Control Statements
C# Language Loops
C# Language Exception Handling
C# Language Inheritance
C# Language Resource Management
C# Language Delegates
C# Language Events
C# Language Generics
C# Language C++/CLI Mixing Native and Managed Code
C# Language Summary
C# Language Windows Vista
C# Language Vista Bridge
C# Language User Account Control
C# Language Directory Structure
C# Language New Controls and Dialogs
C# Language Search
C# Language Summary
C# Language Language Integrated Query
C# Language Traditional Queries
C# Language LINQ Query
C# Language Query Expressions
C# Language Extension Methods
C# Language Standard Query Operators
C# Language Lambda Expressions
C# Language Deferred Query Execution
C# Language Expression Trees
C# Language Type Inference
C# Language Object and Collection Initializers
C# Language Anonymous Types
C# Language Summary
C# Language Index
C# Language A
C# Language B
C# Language C
C# Language D
C# Language E
C# Language F
C# Language G
C# Language H
C# Language I
C# Language J
C# Language K
C# Language L
C# Language M
C# Language N
C# Language O
C# Language P
C# Language Q
C# Language R
C# Language S
C# Language T
C# Language U
C# Language V
C# Language W
C# Language X
C# Language Y
C# Language Z
C# Language
C# Language
Previous PagePrevious
Next PageNext

Interfaces

As mentioned earlier, by deriving from an interface, a class is declaring that it implements certain functions. Because not all object-oriented languages support interfaces, this section examines C#’s implementation of interfaces in detail.

Tip 

Developers familiar with COM should be aware that, although conceptually C# interfaces are similar to COM interfaces, they are not the same thing. The underlying architecture is different. For example, C# interfaces are not derived from IUnknown. A C# interface provides a contract stated in terms of .NET functions. Unlike a COM interface, a C# interface does not represent any kind of binary standard.

This section illustrates interfaces by presenting the complete definition of one of the interfaces that has been predefined by Microsoft, System.IDisposable. IDisposable contains one method, Dispose(), which is intended to be implemented by classes to clean up code:


public interface IDisposable
{
   void Dispose();
}

This code shows that declaring an interface works syntactically in pretty much the same way as declaring an abstract class. You should be aware, however, that it is not permitted to supply implementations of any of the members of an interface. In general, an interface can only contain declarations of methods, properties, indexers, and events.

You can never instantiate an interface; it only contains the signatures of its members. An interface has neither constructors (how can you construct something that you can’t instantiate?) nor fields (because that would imply some internal implementation). An interface definition is also not allowed to contain operator overloads, although that’s not because there is any problem in principle with declaring them - there isn’t; it is because interfaces are usually intended to be public contracts, and having operator over-loads would cause some incompatibility problems with other .NET languages, such as Visual Basic .NET, which do not support operator overloading.

It is also not permitted to declare modifiers on the members in an interface definition. Interface members are always implicitly public, and cannot be declared as virtual or static. That’s up to implementing classes to decide. It is therefore fine for implementing classes to declare access modifiers, as is done in the example in this section.

Take for example IDisposable. If a class wants to declare publicly that it implements the Dispose() method, it must implement IDisposable - which in C# terms means that the class derives from IDisposable.


class SomeClass : IDisposable
{
   // This class MUST contain an implementation of the
   // IDisposable.Dispose() method, otherwise
   // you get a compilation error.
   public void Dispose()
   {
      // implementation of Dispose() method
   }
   // rest of class
}

In this example, if SomeClass derives from IDisposable but doesn’t contain a Dispose() implementation with the exact same signature as defined in IDisposable, you get a compilation error because the class would be breaking its agreed-on contract to implement IDisposable. Of course, there’s no problem for the compiler about a class having a Dispose() method but not deriving from IDisposable. The problem, then, would be that other code would have no way of recognizing that SomeClass has agreed to support the IDisposable features.

Tip 

IDisposable is a relatively simple interface because it defines only one method. Most interfaces will contain more members.

Another good example of an interface is provided by the foreach loop in C#. In principle, the foreach loop works internally by querying the object to find out whether it implements an interface called System.Collections.IEnumerable. If it does, the C# compiler will inject IL code, which uses the methods on this interface to iterate through the members of the collection. If it doesn’t, foreach will raise an exception. The IEnumerable interface is examined in more detail in Chapter 10, “Collections.” It’s worth pointing out that both IEnumerable and IDisposable are somewhat special interfaces to the extent that they are actually recognized by the C# compiler, which takes account of these interfaces in the code that it generates. Obviously, any interfaces that you define yourself won’t be so privileged!

Defining and Implementing Interfaces

This section illustrates how to define and use interfaces through developing a short program that follows the interface inheritance paradigm. The example is based on bank accounts. Assume that you are writing code that will ultimately allow computerized transfers between bank accounts. And assume for this example that there are many companies that may implement bank accounts, but they have all mutually agreed that any classes that represent bank accounts will implement an interface, IBankAccount, which exposes methods to deposit or withdraw money, and a property to return the balance. It is this interface that will allow outside code to recognize the various bank account classes implemented by different bank accounts. Although the aim is to allow the bank accounts to talk to each other to allow transfers of funds between accounts, we won’t introduce that feature just yet.

To keep things simple, you will keep all the code for the example in the same source file. Of course, if something like the example were used in real life, you could surmise that the different bank account classes would not only be compiled to different assemblies but would be hosted on different machines owned by the different banks. (How .NET assemblies hosted on different machines can communicate is explored in Chapter 37, “.NET Remoting.”) That’s all much too complicated for our purposes here. However, to maintain some attempt at realism, you will define different namespaces for the different companies.

To begin, you need to define the IBank interface:


namespace Wrox.ProCSharp
{
   public interface IBankAccount
   {
      void PayIn(decimal amount);
      bool Withdraw(decimal amount);
      decimal Balance
      {
         get;
      }
   }
}

Notice the name of the interface, IBankAccount. It’s a convention that an interface name traditionally starts with the letter I, so that you know that it’s an interface.

Tip 

Chapter 2, “C# Basics,” pointed out that, in most cases, .NET usage guidelines discourage the so-called Hungarian notation in which names are preceded by a letter that indicates the type of object being defined. Interfaces are one of the few exceptions in which Hungarian notation is recommended.

The idea is that you can now write classes that represent bank accounts. These classes don’t have to be related to each other in any way; they can be completely different classes. They will, however, all declare that they represent bank accounts by the mere fact that they implement the IBankAccount interface.

Let’s start off with the first class, a saver account run by the Royal Bank of Venus:


namespace Wrox.ProCSharp.VenusBank
{
   public class SaverAccount : IBankAccount
   {
      private decimal balance;
      public void PayIn(decimal amount)
      {
         balance += amount;
      }
      public bool Withdraw(decimal amount)
      {
         if (balance >= amount)
         {
            balance -= amount;
            return true;
         }
         Console.WriteLine("Withdrawal attempt failed.");
         return false;
      }
      public decimal Balance
      {
         get
         {
            return balance;
         }
      }
      public override string ToString()
      {
         return String.Format("Venus Bank Saver: Balance = {0,6:C}", balance);
      }
   }
}

It should be pretty obvious what the implementation of this class does. You maintain a private field, balance, and adjust this amount when money is deposited or withdrawn. You display an error message if an attempt to withdraw money fails because there is insufficient money in the account. Notice also that, because we want to keep the code as simple as possible, you are not implementing extra properties, such as the account holder’s name! In real life that would be pretty essential information, but for this example it’s unnecessarily complicated.

The only really interesting line in this code is the class declaration:


public class SaverAccount : IBankAccount

You’ve declared that SaverAccount is derived from one interface, IBankAccount, and you have not explicitly indicated any other base classes (which of course means that SaverAccount is derived directly from System.Object). By the way, derivation from interfaces acts completely independently from derivation from classes.

Being derived from IBankAccount means that SaverAccount gets all the members of IBankAccount. But because an interface doesn’t actually implement any of its methods, SaverAccount must provide its own implementations of all of them. If any implementations are missing, you can rest assured that the compiler will complain. Recall also that the interface just indicates the presence of its members. It’s up to the class to decide if it wants any of them to be virtual or abstract (though abstract functions are of course only allowed if the class itself is abstract). For this particular example, you don’t have any reason to make any of the interface functions virtual.

To illustrate how different classes can implement the same interface, assume that the Planetary Bank of Jupiter also implements a class to represent one of its bank accounts - a Gold Account:


namespace Wrox.ProCSharp.JupiterBank
{
   public class GoldAccount : IBankAccount
   {
      // etc
   }
}

We won’t present details of the GoldAccount class here; in the sample code, it’s basically identical to the implementation of SaverAccount. We stress that GoldAccount has no connection with VenusAccount, other than that they happen to implement the same interface.

Now that you have your classes, you can test them out. You first need a couple of using statements:


using System;
using Wrox.ProCSharp;
using Wrox.ProCSharp.VenusBank;
using Wrox.ProCSharp.JupiterBank;

Now you need a Main() method:


namespace Wrox.ProCSharp
{
   class MainEntryPoint
   {
      static void Main()
      {
         IBankAccount venusAccount = new SaverAccount();
         IBankAccount jupiterAccount = new GoldAccount();
         venusAccount.PayIn(200);
         venusAccount.Withdraw(100);
         Console.WriteLine(venusAccount.ToString());
         jupiterAccount.PayIn(500);
         jupiterAccount.Withdraw(600);
         jupiterAccount.Withdraw(100);
         Console.WriteLine(jupiterAccount.ToString());
      }
   }
}

This code (which if you download the sample, you can find in the file BankAccounts.cs) produces this output:

C:> BankAccounts
Venus Bank Saver: Balance = ÂŁ100.00
Withdrawal attempt failed.
Jupiter Bank Saver: Balance = ÂŁ400.00

The main point to notice about this code is the way that you have declared both your reference variables as IBankAccount references. This means that they can point to any instance of any class that implements this interface. It does, however, mean that you can only call methods that are part of this interface through these references - if you want to call any methods implemented by a class that are not part of the interface, you need to cast the reference to the appropriate type. In the example code, you were able to call ToString() (not implemented by IBankAccount) without any explicit cast, purely because ToString() is a System.Object method, so the C# compiler knows that it will be supported by any class (put differently, the cast from any interface to System.Object is implicit). Chapter 6, “Operators and Casts,” covers the syntax for how to perform casts.

Interface references can in all respects be treated like class references - but the power of an interface reference is that it can refer to any class that implements that interface. For example, this allows you to form arrays of interfaces, where each element of the array is a different class:


IBankAccount[] accounts = new IBankAccount[2];
accounts[0] = new SaverAccount();
accounts[1] = new GoldAccount();
Note, however, that we'd get a compiler error if we tried something like this
accounts[1] = new SomeOtherClass();    // SomeOtherClass does NOT implement
                                              // IBankAccount: WRONG!!

This causes a compilation error similar to this:

Cannot implicitly convert type 'Wrox.ProCSharp. SomeOtherClass' to
'Wrox.ProCSharp.IBankAccount'

Derived Interfaces

It’s possible for interfaces to inherit from each other in the same way that classes do. This concept is illustrated by defining a new interface, ITransferBankAccount, which has the same features as IBankAccount but also defines a method to transfer money directly to a different account:


namespace Wrox.ProCSharp
{
   public interface ITransferBankAccount : IBankAccount
   {
      bool TransferTo(IBankAccount destination, decimal amount);
   }
}

Because ITransferBankAccount is derived from IBankAccount, it gets all the members of IBankAccount as well as its own. That means that any class that implements (derives from) ITransferBankAccount must implement all the methods of IBankAccount, as well as the new TransferTo() method defined in ITransferBankAccount. Failure to implement all of these methods will result in a compilation error.

Note that TransferTo() method uses an IBankAccount interface reference for the destination account. This illustrates the usefulness of interfaces: when implementing and then invoking this method, you don’t need to know anything about what type of object you are transferring money to - all you need to know is that this object implements IBankAccount.

To illustrate ITransferBankAccount, assume that the Planetary Bank of Jupiter also offers a current account. Most of the implementation of the CurrentAccount class is identical to the implementations of SaverAccount and GoldAccount (again, this is just in order to keep this example simple - that won’t normally be the case), so in the following code just the differences are highlighted:

public class CurrentAccount : ITransferBankAccount
{
   private decimal balance;
   public void PayIn(decimal amount)
   {
      balance += amount;
   }
   public bool Withdraw(decimal amount)
   {
      if (balance >= amount)
      {
         balance -= amount;
         return true;
      }
      Console.WriteLine("Withdrawal attempt failed.");
      return false;
   }
   public decimal Balance
   {
      get
      {
         return balance;
      }
   }
    public bool TransferTo(IBankAccount destination, decimal amount)
    {
       bool result;
       if ((result == Withdraw(amount))
          destination.PayIn(amount);
       return result;
   }
   public override string ToString()
   {
      return String.Format("Jupiter Bank Current Account: Balance = {0,6:C}",
                                                                      balance);
   }
}

The class can be demonstrated with this code:


static void Main()
{
   IBankAccount venusAccount = new SaverAccount();
   ITransferBankAccount jupiterAccount = new CurrentAccount();
   venusAccount.PayIn(200);
   jupiterAccount.PayIn(500);
   jupiterAccount.TransferTo(venusAccount, 100);
   Console.WriteLine(venusAccount.ToString());
   Console.WriteLine(jupiterAccount.ToString());
}

This code (CurrentAccount.cs) produces the following output, which, as you can verify, shows that the correct amounts have been transferred:

C:> CurrentAccount
Venus Bank Saver: Balance = ÂŁ300.00
Jupiter Bank Current Account: Balance = ÂŁ400.00

Previous PagePrevious
Next PageNext