Part 1. Developing applications that use types and collections edit

1.1 Manage data in a .NET Framework application by using the .NET Framework 2.0 system types. edit

Data types are separated into value types and reference types. Value types are either stack-allocated or allocated inline in a structure.

Reference types are heap-allocated. Both reference and value types are derived from the ultimate base class System.Object.

In cases where a value type needs to act like an object, a wrapper that makes the value type look like a reference object is allocated on the heap, and the value type's value is copied into it. The wrapper is marked so that the system knows that it contains a value type. This process is known as boxing, and the reverse process is known as unboxing. Boxing and unboxing allow any type to be treated as an object.

In .Net and mono (nearly) everything is a Type. The key to finding out about types is the System.Type class. This class can be used to investigate a type. The quickest way to get hold of a type in c# is to use the typeof operator. This operator returns a System.Type object.

using System;

namespace OpenEd.Ms70536.Part1.Section1
{
        public class TypeQuery
        {
                public static void Main ()
                {
                        // Getting an instance of Type in c#.
                        Console.WriteLine (typeof (Type).FullName);
                        // Getting an instance is more complicated using the CTS.
                        Console.WriteLine (Type.GetType ("System.Type").FullName);
                }
        }
}

1.1.1 Value types edit

We can investigate types using System>Type and some reflection.

using System;

1.1.2 Reference types edit

1.1.3 Attributes edit

1.1.4 Generic types edit

1.1.5 Exception classes edit

See: System.Exception

All exceptions derive from the System.Exception class. This class has three constructors to throw a new exception either the first or second constructor can be used. To throw a nested exception the third constructor is used. Each of the constructors is illustrated below.

using System;

public class ThrowSimpleException
{
        public static void Main ()
        {
                throw new Exception();
        }
}
using System;

public class ThrowExceptionWithMessage
{
        public static void Main ()
        {
                throw new Exception ("Exception with message was thrown.");
        }
}
using System;

public class ThrowNestedException
{
        public static void Main ()
        {
                Exception innerException = new Exception ("Inner exception message.");
                throw new Exception ("Outer exception message.", innerException);
        }
}

In practice exceptions that are thrown should derive from System.Exception. It is bad practice to throw System.Exception directly.

1.1.6 Boxing and UnBoxing edit

1.1.7 TypeForwardedToAttribute Class edit

1.2 Manage a group of associated data in a .NET Framework application by using collections. edit

Managing groups of data as a unit where each data item can be accessed is a common operation. The System.Collections namespace provides several different types for managing collections. The collections are related to one another by the fact that they implement IEnumrable and ICollection (Check this).

The three interfaces IList, ICollection and IDictionary are structured in the following way:

ICollection : IEnumerable

IList : ICollection, IEnumerable

IDictionary : ICollection, IEnumerable




                 O-- IEnumerable
                 ^
                 |
             O-- ICollection
             ^
             |
    |--------|--------|
    |                 |
O-- IDictionary   O-- IList

The main classes of System.Collections are as follows:

ArrayList : IList
BitArray : ICollection
HashTable : IDictionary
Queue : ICollection
SortedList : IDictionary
Stack : ICollection
ICollection - BitArray, Queue, Stack
IList - ArrayList
IDictionary - HashTable, SortedList
ArrayList class edit

ArrayList implements a variable-size IList that uses an array of objects to store the elements. A ArrayList has a ArrayList.Capacity, which is the allocated length of the internal array. The total number of elements contained by a list is its ArrayList.Count. As elements are added to a list, its capacity is automatically increased as required by reallocating the internal array.

Collection interfaces edit
  • ICollection interface and IList interface
public interface ICollection
{
        int Count { get; }
        bool IsSynchronized { get; }
        object SyncRoot { get; }
        void CopyTo (Array array, int index);
}

public interface IList
{
        bool IsFixedSize { get; }
        bool IsReadOnly { get; }
        object this [ int index ] { get; set; }
        // TODO: Add methods.
}
  • IComparer interface and IEqualityComparer interface
  • IDictionary interface and IDictionaryEnumerator interface
  • IEnumerable interface and IEnumerator interface
public interface IEnumerable
{
        IEnumerator GetEnumerator ();
}

public interface IEnumerator
{
        Object Current { get; }
        bool MoveNext ();
        void Reset ();
}
Iterators edit
Hashtable class edit

A Hashtable represents a dictionary with a constant lookup time that contains entries of associated keys and values. The type of each entry in a Hashtable is DictionaryEntry. A statement that exposes each element in the collection is required to iterate over this type.

CollectionBase class and ReadOnlyCollectionBase class edit
DictionaryBase class and DictionaryEntry class edit
Comparer class edit
Queue class edit
SortedList class edit
BitArray class edit

The System.Collections.BitArray implements a collection of boolean values. There are a number of different constructors for a BitArray. The BitArray( ) creates ... The methods of a BitArray allow a bitwise operation to be performed on the BitArray.

using System;
using System.Collections;

namespace OpenEd.Ms70536.Part1.Section2
{
        public class BitArrayExample
        {
                public static void Main ()
                {
                        BitArray bitArray = new BitArray (new byte [] {byte.Parse ("25")});
                        Console.WriteLine ("bitArray.Count: {0}", bitArray.Count);
                        for (int i = 0; i < bitArray.Count; i++)
                                Console.WriteLine ("bitArray [{0}]: {1}", i, bitArray [i]);
                }
        }
}

Compiling and running this example gives the following output:

~/work/70-536/70-536.1/70-536.1.2> gmcs bitarrayfrombyte.cs
~/work/70-536/70-536.1/70-536.1.2> mono bitarrayfrombyte.exe
bitArray.Count: 8
bitArray [0]: True
bitArray [1]: False
bitArray [2]: False
bitArray [3]: True
bitArray [4]: True
bitArray [5]: False
bitArray [6]: False
bitArray [7]: False

Stack class edit

The stack is a collection supporting only the push, pop, and peek operations. The push method puts an object onto the end of the stack. The peek method returns the most recent object placed on the stack. The pop method removes the most recent object placed on the stack and returns it.

1.3 Improve type safety and application performance in a .NET Framework application by using generic collections edit

There is often a need to have a collection only store objects of a given type. For example an ArrayList might be used to store only strings.

        ArrayList stringArray = new ArrayList ();
        stringArray.Add ("String 1.");
        stringArray.Add ("String 2.");
        stringArray.Add ("String 3.");

However this is not type safe as at any point in the lifetime of the stringArray object an object that is not a string can added.

There is also the convenience of having to cast down the items retreived from the stringArray.

        string string2 = (string) stringArray [1];

In earlier versions of c# the only way to have type safe collections was either to wrap an existing collection or derive from an existing collection.

        public class StringArray
        {
                private ArrayList stringArray;

                public StringArray () {}
        }
Collection.Generic interfaces edit
  • Generic IComparable interface (Refer System Namespace)
  • Generic ICollection interface and Generic IList interface
  • Generic IComparer interface and Generic IEqualityComparer interface
  • Generic IDictionary interface
  • Generic IEnumerable interface and Generic IEnumerator interface
  • IHashCodeProvider interface
Generic Dictionary edit
  • Generic Dictionary class and Generic Dictionary.Enumerator structure
  • Generic Dictionary.KeyCollection class and Dictionary.KeyCollection.Enumerator structure
  • Generic Dictionary.ValueCollection class and Dictionary.ValueCollection.Enumerator structure
Generic Comparer class and Generic EqualityComparer class edit
Generic KeyValuePair structure edit
Generic List class, Generic List.Enumerator structure, and Generic SortedList class edit
Generic Queue class and Generic Queue.Enumerator structure edit
Generic SortedDictionary class edit
Generic LinkedList edit
  • Generic LinkedList class
  • Generic LinkedList.Enumerator structure
  • Generic LinkedListNode class
Generic Stack class and Generic Stack.Enumerator structure edit

1.4 Manage data in a .NET Framework application by using specialized collections. edit

Specialized String classes edit
  • StringCollection class
  • StringDictionary class
  • StringEnumerator class
Specialized Dictionary edit
  • HybridDictionary class
  • IOrderedDictionary interface and OrderedDictionary class
  • ListDictionary class
Named collections edit
  • NameObjectCollectionBase class
  • NameObjectCollectionBase.KeysCollection class
  • NameValueCollection class
CollectionsUtil edit
BitVector32 structure and BitVector32.Section structure edit

1.5 Implement .NET Framework interfaces to cause components to comply with standard contracts. edit

IComparable interface edit
IDisposable interface edit
IConvertible interface edit
ICloneable interface edit
IEquatable interface edit
IFormattable interface edit

1.6 Control interactions between .NET Framework application components by using events and delegates. edit

Delegate class edit

A delegate is similar to a typed function pointer.

The ThermoStat class

using System.Threading;
 
namespace OpenEd.Ms70536.Part1.Section6
{
    public delegate void ThermostatChangedEventHandler(ThermostatState newState);

    public class Thermostat
    {
        private ThermostatState state = ThermostatState.Open;

        public ThermostatChangedEventHandler ThermostatChanged;

        public void MonitorTemperature()
        {
            while (true)
            {
                Thread.Sleep(2000);
                FlipState();
                if (ThermostatChanged != null)
                {
                    ThermostatChanged(state);
                }
            }
        }

        private void FlipState()
        {
            if (state == ThermostatState.Open)
            {
                state = ThermostatState.Closed;
            }
            else
            {
                state = ThermostatState.Open;
            }
        }
    }
}

A delegate allows the act of calling a method to be delegated to someone else.

public delegate void TemperatureChangedEventHandler(double temperature);

 public class ClientServer
 {
         public static void Main ()
         {
                 Server server = new Server ();
                 WriteMessage (server.GetMessage ());
                 // TODO: poll servers here.
           }
  
         public void WriteMessage (string message)
         {
                 Console.WriteLine (message);
         }
 }

 public class EventHandlingClient
 {
        public static void Main ()
        {
               Server server = new Server ();
               MessageReceived += new MessageReceivedEventHandler (WriteMessage);
               // TODO: loop waiting for servers here.
        }
 }
Delegate class - test driven edit

In this section we'll explore delegates using unit tests. The first question we'll look at is when are delgates created?

A delegate is created when an method is added to the invocation list. The delegate is distroyed when there are no more methods in the invocation list.

using NUnit.Framework;

namespace OpenEd.Ms70536.Part1.Section6
{
	[TestFixture]
	public class ThermostatTests
	{
		[Test]
		public void AddingHandlerCreatesDelegate ()
		{
			Thermostat thermostat = new Thermostat ();
			Assert.IsNull (thermostat.ThermostatChanged);
			thermostat.ThermostatChanged += new ThermostatChangedEventHandler (OnThermostatChanged);
			Assert.IsNotNull (thermostat.ThermostatChanged);
			thermostat.ThermostatChanged -= new ThermostatChangedEventHandler (OnThermostatChanged);
			Assert.IsNull (thermostat.ThermostatChanged);
		}

        	public void OnThermostatChanged(ThermostatState newState)
        	{
        	}
	}
}
EventArgs class edit

The EventArgs class is a base class for use in the pattern described in the next section. To pass arguments sub classes are derived from the EventArgs class.

public class ThermostatChangedEventArgs : EventArgs
{
        private ThermostatState newState;

        public ThermostatChangedEventArgs (ThermostatState newState)
        {
                this.newState = newState;
        }

        public ThermostatState NewState
        {
                get { return newState; }
        }
}
EventHandler delegates edit

The EventHanlder is part of a pattern for handling events that is aimed at reducing the proliferation of different delegates. In this pattern there is one delegate, the EventHandler delegate.

public delegate void EventHandler (object sender, EventArgs e)