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); } } } We can investigate types using System>Type and some reflection. using System; 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. 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: The main classes of System.Collections are as follows: 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. 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 (); } 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. 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 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. 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 () {} } 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 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 LinkedList class Generic LinkedList.Enumerator structure Generic LinkedListNode class StringCollection class StringDictionary class StringEnumerator class HybridDictionary class IOrderedDictionary interface and OrderedDictionary class ListDictionary class NameObjectCollectionBase class NameObjectCollectionBase.KeysCollection class NameValueCollection class 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. } } 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) { } } } 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; } } } 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)
{'wiki_source': 'wikiversity', 'other_info': "{'content_model': 'wikitext', 'language': 'en', 'title': 'MS 70-536.1', 'type': 'text'}"}