70-536 Test Part 2

  • June 2020
  • PDF

This document was uploaded by user and they confirmed that they have the permission to share it. If you are author or own the copyright of this book, please report to us by using this DMCA report form. Report DMCA


Overview

Download & View 70-536 Test Part 2 as PDF for free.

More details

  • Words: 27,460
  • Pages: 102
IDictionaryEnumerator Interface Enumerates the elements of a nongeneric dictionary. Namespace: System.Collections Assembly: mscorlib (in mscorlib.dll) Syntax Visual Basic (Declaration) _ Public Interface IDictionaryEnumerator _ Implements IEnumerator Visual Basic (Usage) Dim instance As IDictionaryEnumerator C# [ComVisibleAttribute(true)] public interface IDictionaryEnumerator : IEnumerator Remarks vb#c# The foreach statement of the C# language (for each in Visual Basic) hides the complexity of the enumerators. Therefore, using foreach is recommended instead of directly manipulating the enumerator. Enumerators can be used to read the data in the collection, but they cannot be used to modify the underlying collection. Initially, the enumerator is positioned before the first element in the collection. The Reset method also brings the enumerator back to this position. At this position, calling the Current property throws an exception. Therefore, you must call the MoveNext method to advance the enumerator to the first element of the collection before reading the value of Current. Current returns the same object until either MoveNext or Reset is called. MoveNext sets Current to the next element. If MoveNext passes the end of the collection, the enumerator is positioned after the last element in the collection and MoveNext returns false. When the enumerator is at this position, subsequent calls to MoveNext also return false. If the last call to MoveNext returned false, calling Current throws an exception. To set Current to the first element of the collection again, you can call Reset followed by MoveNext. An enumerator remains valid as long as the collection remains unchanged. If changes are made to the collection, such as adding, modifying, or deleting elements, the enumerator is irrecoverably invalidated and the next call to MoveNext or Reset throws an InvalidOperationException. If the collection is modified between MoveNext and Current, Current returns the element that it is set to, even if the enumerator is already invalidated. The enumerator does not have exclusive access to the collection; therefore, enumerating through a collection is intrinsically not a thread-safe procedure. Even when a collection is synchronized, other threads can still modify the collection, which causes the enumerator to throw an exception. To guarantee thread safety during enumeration, you can either lock the collection during the entire enumeration or catch the exceptions resulting from changes made by other threads. Notes to Implementers: The Current property that is inherited from IEnumerator returns an Object that is a boxed DictionaryEntry, similar to the return value of the Entry property. Examples This code example shows how to define a dictionary enumerator that implements the IDictionaryEnumerator interface.

Visual Basic Private Class SimpleDictionaryEnumerator Implements IDictionaryEnumerator ' A copy of the SimpleDictionary object's key/value pairs. Dim items() As DictionaryEntry Dim index As Integer = -1 Public Sub New(ByVal sd As SimpleDictionary) ' Make a copy of the dictionary entries currently in the SimpleDictionary object. items = New DictionaryEntry(sd.Count - 1) {} Array.Copy(sd.items, 0, items, 0, sd.Count) End Sub ' Return the current item. Public ReadOnly Property Current() As Object Implements IDictionaryEnumerator.Current Get ValidateIndex() Return items(index) End Get End Property ' Return the current dictionary entry. Public ReadOnly Property Entry() As DictionaryEntry Implements IDictionaryEnumerator.Entry Get Return Current End Get End Property ' Return the key of the current item. Public ReadOnly Property Key() As Object Implements IDictionaryEnumerator.Key Get ValidateIndex() Return items(index).Key End Get End Property ' Return the value of the current item. Public ReadOnly Property Value() As Object Implements IDictionaryEnumerator.Value Get ValidateIndex() Return items(index).Value End Get End Property ' Advance to the next item. Public Function MoveNext() As Boolean Implements IDictionaryEnumerator.MoveNext If index < items.Length - 1 Then index = index + 1 Return True End If Return False End Function ' Validate the enumeration index and throw an exception if the index is out of range.

Private Sub ValidateIndex() If index < 0 Or index >= items.Length Then Throw New InvalidOperationException("Enumerator is before or after the collection.") End If End Sub ' Reset the index to restart the enumeration. Public Sub Reset() Implements IDictionaryEnumerator.Reset index = -1 End Sub End Class Public Function GetEnumerator() As IDictionaryEnumerator Implements IDictionary.GetEnumerator 'Construct and return an enumerator. Return New SimpleDictionaryEnumerator(Me) End Function ' ICollection Members Public ReadOnly Property IsSynchronized() As Boolean Implements IDictionary.IsSynchronized Get Return False End Get End Property Public ReadOnly Property SyncRoot() As Object Implements IDictionary.SyncRoot Get Throw New NotImplementedException() End Get End Property Public ReadOnly Property Count() As Integer Implements IDictionary.Count Get Return ItemsInUse End Get End Property Public Sub CopyTo(ByVal array As Array, ByVal index As Integer) Implements IDictionary.CopyTo Throw New NotImplementedException() End Sub ' IEnumerable Members Public Function GetEnumerator1() As IEnumerator Implements IEnumerable.GetEnumerator ' Construct and return an enumerator. Return Me.GetEnumerator() End Function End Class C# private class SimpleDictionaryEnumerator : IDictionaryEnumerator { // A copy of the SimpleDictionary object's key/value pairs. DictionaryEntry[] items; Int32 index = -1;

public SimpleDictionaryEnumerator(SimpleDictionary sd) { // Make a copy of the dictionary entries currently in the SimpleDictionary object. items = new DictionaryEntry[sd.Count]; Array.Copy(sd.items, 0, items, 0, sd.Count); } // Return the current item. public Object Current { get { ValidateIndex(); return items[index]; } } // Return the current dictionary entry. public DictionaryEntry Entry { get { return (DictionaryEntry) Current; } } // Return the key of the current item. public Object Key { get { ValidateIndex(); return items[index].Key; } } // Return the value of the current item. public Object Value { get { ValidateIndex(); return items[index].Value; } } // Advance to the next item. public Boolean MoveNext() { if (index < items.Length - 1) { index++; return true; } return false; } // Validate the enumeration index and throw an exception if the index is out of range. private void ValidateIndex() { if (index < 0 || index >= items.Length) throw new InvalidOperationException("Enumerator is before or after the collection."); } // Reset the index to restart the enumeration. public void Reset() { index = -1; } } public IDictionaryEnumerator GetEnumerator() { // Construct and return an enumerator. return new SimpleDictionaryEnumerator(this); } #endregion #region ICollection Members public bool IsSynchronized { get { return false; } } public object SyncRoot { get { throw new NotImplementedException(); } } public int Count { get { return ItemsInUse; } } public void CopyTo(Array array, int index) { throw new NotImplementedException(); } #endregion

}

#region IEnumerable Members IEnumerator IEnumerable.GetEnumerator() { // Construct and return an enumerator. return ((IDictionary)this).GetEnumerator(); } #endregion

Event Summary An event is basically a list of delegates. Technically, it is a multicast delegate. However, the event keyword allows the compiler to encapsulate the delegate to control how it is accessed. The object that has the event is called the publisher. The object that handles the event is called the subscriber. An event allows a publisher to call a subscriber's event handler without knowing anything about the subscriber. For example, a Button object with a Click event can call all the ClickEventHandlers without knowing the class or method names which handle the event. It is the subscriber's responsibility to subscribe to the event. The publisher simply raises the event at the appropraite time. Whenever the event is raised, each delegate that is in the event's list will be called. Remarks The event keyword encapsulates the event delegate. With it, the compiler only allows += and -= operations outside the class. Therefore, only the publisher can access the delegate object directly to call it or edit the list of delegates. Code Examples .Net Event Conventions: Name delegates used for an event type with a suffix of "EventHandler" Name custom EventArgs with a suffix of "EventArgs" and inherit from EventArgs EventHandler delegates should always have two parameters: object sender, and ___EventArgs e Example Names: // Event Handler Delegate Declaration public delegate void MouseClickedEventHandler( object sender, MouseClickedEventArgs e ); // Event Args Declaration public class MouseClickedEventArgs : EventArgs { //... } // Event Declaration public event MouseClickedEventHandler MouseClicked; Declare a basic event public event EventHandler Changed;Declare a Mouse Clicked event public event MouseClickEventHandler MouseClicked;Subscribe to an event

public void Subscribe() { // Subscribe to the event btnCancel.Click += new EventHandler( CancelClick ); } // The event handler void CancelClick( object sender, EventArgs e ) { //... }Declare a delegate and an event with custom EventArgs // Declare a delegate inside the namespace public delegate void StatusChangedEventHandler( object sender, StatusChangedEventArgs e ); // StatusChangedEventArgs is at the bottom of this example // The event publisher public class ClassWithStatus { // Declare the event public event StatusChangedEventHandler StatusChanged; } // Declare the custom event args class // It should inherit from EventArgs public class StatusChangedEventArgs : EventArgs { private readonly bool _isDone; public StatusChangedEventArgs( bool isDone ) { _isDone = isDone; } public bool IsDone { get { return _isDone; } } }Declare an event that uses generic EventHandler with custom EventArgs // The event publisher public class TreeNode { // Declare the event public event EventHandler<ExpandedEventArgs> Expanded; } // The custom event args class public class ExpandedEventArgs : EventArgs { private readonly TreeNode _expandingNode; public StatusChangedEventArgs( TreeNode expandingNode )

{

_expandingNode = expandingNode;

}

}

public TreeNode ExpandingNode { get { return _expandingNode; } }

Exam 70-536 Study Guide: Skill Set 1 This is the first skill set for the the Microsoft .NET Framework 2.0—Application Development Foundation Exam. This skill set involves using the built-in system data types, collections of data types, interfaces, and delegates and events. Developing applications that use system types and collections Manage data in a .NET Framework application by using the .NET Framework 2.0 system types. (System) Manage a group of associated data using collections in a .NET Framework application. (System.Collections) Use generic collections to improve type safety and application performance in a .NET Framework application. (System.Collections.Generic) Use specialized collections to manage data in a .NET Framework application. (System.Collections.Specialized) Implement .NET Framework interfaces to cause components to comply with standard contracts. (System) Use events and delegates to control interactions between .NET Framework application components. (System) Exception classes When writing any piece of software, at some stage errors occur when the application is run. This is through no fault in the programming of the code, but rather through unexpected actions on the part of the user. Unexpected actions may include selecting a file that does not exist or entering a letter where a number is expected. These unexpected actions can be handled in one of two ways, either by preemptive programming or by using exceptions. The .NET Framework provides an Exception class in the System namespace to handle exceptions. Preemptive programming requires the programmer to think about everything that could possibly go wrong when the application is run. Let us consider the first of the two examples cited above. To find out if a file exists, we can invoke the Exists() function of the File class, passing to it the string supplied to us by the user: if ( !File.Exists (file_name)) { // The source file does not exist } else { // The source file exists }The if statement catches the error; but, what should we do with it? What about if the if statement was not inverted? This would cause a programming bug that would not be caught until runtime and would cause an exception. When a program error occurs, either the system or the currently executing application reports it by throwing an exception containing information about the error. Once thrown, an exception is handled by the application or by the default exception handler.

Even if you remove all bugs and anticipate all user errors, you will still run into predictable but unpreventable problems, such as running out of memory or attempting to open a file that no longer exists. You cannot prevent exceptions, but you can handle them so that they do not bring down your program. Benefits of exceptions Exceptions provide the ability to handle or clean up code in a localized place. Also, they allow clean-up code to execute in case of error. The application becomes easier to write and maintain when clean-up code is in a centralized place. Also—and maybe more importantly—, exceptions can be used to find bugs within the code; because, the CLR walks up the stack of the thread to get the call history. With this, it is possible to find the location of the failure within the code. Further, it is possible to add additional information within the exception, so that a developer can describe the kind of error more precisely. The biggest problem with exceptions is performance because of some information overhead. So, they should be used only where preemptive programming is inappropriate. Unfortunately, most developers tend to use exceptions improperly—i.e. catch (Exception e); which will be discussed later—or too seldom, so debugging proves harder. Using exceptions Execptions are used within the try-, catch-, and finally-code blocks. The Exception is created and thrown within the try-block. If the Exeption is thrown, the code within the try-block stops and the finally-block executes. After this, the first match to a sequence of catch-blocks gets executed, bringing the application into a stable state; because, the code in the try-block didn't finish. The structure of this looks like the following: void example() { try { // Here is where the Exception would be thrown } catch (ArgumentOutOfRangeException e) { // This block executes if the Exception is of type // ArgumentOutOfRangeException. Otherwise, the program // jumps to the next catch-block. } catch (InvalidCastException e) { // This block executes if the Exception is of type // InvalidCastException. The Exception is stored // within the Variable "e". This is needed e.g. to query // and extend the Error Message of the Exception. } catch (Exception e) { // Because all Exceptions in .NET derive from Exception, // this block will handle all .NET Exceptions. // This kind of Exception cannot be handled and must be // rethrown. Think of an OutOfMemoryException, where // creating a Window showing the Exception makes it even

// worse. throw; } catch { // Catches all kinds of exceptions, even when they are not // CLS-comform, which can appear only when calling // unmanaged code. // This can not be handled correctly, either. throw; } finally { // This code will execute in any case, // whether an Exception was thrown or not. } }The catch block can handle the Exception in one of three ways: Rethrow the same exception to notify the code which is prior in the call stack. Throw another exception with more precise information. The current Exception can be appended. Handle the exception and continue with the code after the try/catch/finally-block. Important: Never handle an Exception of type System.Exception, because this is not—or, at least, hardly—possible. Examples are: OutOfMemoryException Occurs when the CLR has no free memory available to create new objects on the Heap. Even the garbage collector does not help at this point. The best thing you can do is to terminate the program (thread). If you want to develop a server application, it is best to develop also a watch dog program or to register the program as a Windows service, so that it will restart the program or even the entire server. StackOverflowException Similar to the OutOfMemoryException; but this time, there is no space on the Stack. This makes it also impossible to call the finally-block. Therefore the program can be in an undefined state and should be terminated. ExecuteEngineException This Exception throws when the CLR detects an error like a corrupted data-structure (e.g. a buffer overflow) or a bug within the CLR itself. Anyway, in that case, the CLR will call a debugger or terminate the whole process without executing any catch- or finally-blocks. Also, catching such an Exception and checking the type of it afterwards is possible; but, it is not a pretty programming style. The System.Exception class The System.Exception class is small class representing information about the kind of Exception. The properties are: Message A string representing a human-readable message. Source The name of the assembly where the exception was thrown. Not available in the Mobile .Net Framework. StackTrace Names of the calling functions as found on the call stack. TargetSite The method that throws the Exception originally. Not available in the Mobile .Net Framework. HelpLink

A link to a resource (e.g. a Web site or a help file) which provides further information. Not available in the Mobile .Net Framework. InnerException This field is normally set to null. If not, this indicates that this Exception was thrown because of another Exception whith is now stored within this property. Additional to this property, you can also use the GetBaseException() function which returns the innermost Exception. HResult This is the HResult whitch will get returned from a COM object. This property is only needed when interoperating with COM code. Handling exceptions As stated before we have three possibilities to handle a Exception: Rethrow Throw new exception Handle the exception We will look at some examples in the following sections. Rethrow an Exception One way to use Exception is to catch an Exception and run exception-specific code. When this is done, the same exception is thrown again and "bubbling up" the call stack. public String ReadFirstLine (String FileName) { try { FileStream fs = new FileStream (FileName, FileMode.Open); } catch (Exception e) { // override the Message of the Exception e.Message = "Could not open the file."; // rethrow the same exception throw; } // the file is open now try { String FirstLine = fs.ReadLine(); } catch (Exception e) { e.Message = "Could not read first line of file."; throw; } finally { // close the FileStream in each case fs.Close(); } return FirstLine; }Even if we catch an System.Exception here, it is not a problem; because, we can simply rethrow it. Another problem you should respect within catch(Exception e) blocks is that you should avoid creating new objects within the heap (reference types). Remember the OutOfMemoryException example.

Sometimes, it is necessary to set data back to its original state when an exception occurs. In that case, you create a backup of the properties you want to change and restore them in case of a exception. private Byte[10] ReadNextTenBytes(FileStream fs) { Int64 PositionBeforeOutput = fs.Position; try { var Output = new Byte[10]; fs.Read (Output, fs.Position, 10); } catch { fs.Position = PositionBeforeOutput; throw; } return Output; }Throw a new Exception Sometimes the Exception thrown by a function does not describe the core of the problem well enough. In such a case, you catch the exception and throw a more describing one instead. public Int32 Inverse(Int32 Number) { Int32 Inverse; try { Inverse = 1 / Number; } catch (DivideByZeroException e) { ArgumentOutOfRangeException ae = new ArgumentOutOfRangeException ( "Number can't be Zero", e); throw ae; } return Inverse; }Notice that when throwing a new exception or when rethrowing the original Exception using code like catch (Exception e){throw e;} properties like StackTrace and Source will get overridden by the information of the current function. Also, in most cases, you should set the InnerException property (second argument of the constructor) for further reference. Handle the Exception In some special cases, it is possible to bring the application into a stable state, even when an Exception has occurred. public Int32[] ParseNumbers(String[] Numbers) { Int32[] ParsedNumbers = new Int32[]; Int32 ParsedNumber; int elements = 0; foreach (Int32 Number in Numbers) { try {

ParsedNumber = Int32.Parse(Number); } catch (FormatException e) { continue; } catch (OverflowException e) { continue; } ParsedNumbers[elements++] = ParsedNumber;

} return ParsedNumbers; }This code takes an array of integers which are presented as a String array. The code tries to parse every string within this array one after the other. If this fails, the Int32.Parse() method will probably throw an Exception of type FormatException or OverflowException. This means the string is not parseable. This does not matter in that case; and, we simply repeat with parsing the next String in the array. Other exceptions will not be handled. They continue bubbling up the call stack. Notice, that in this example, we do not need access to the Exception; so, we could rewite, e.g. catch (FormatException e) as catch(FormatException). Catch filter In C#, the catch block filters for a specific type of Exception and runs the first match. But, the .NET CLR supports also more complex catch filters which you can use from Visual Basic .NET, C++ with managed extensions, or IL. In VB .Net this might look like: Catch e as Exception When x = 0In that example, the catch code executes only if the Exception is of type System.Exception and the variable x is equal to zero. In C#, you need to rewrite this using an additional if block. Creating and throwing an Exception The first thing when wanting to create a Exception is to find the best fitting one for your purpose. Therefore you can use the List Exceptions Program to find all the common ones. Then, read the result and select one. If you want to be more specific by providing a more meaningful name or additional properties, derive a new Exception from the next best fitting one. Note, that in the worst case the best fitting Exception is not System.Exception or System.SystemException, which is a reserved behavior for the .NET Framework internal exceptions from which you should derive, but System.ApplicationException. Custom exceptions should always be serializeable, so that the exception can also used in an distributed environment like a Web service. If you decided on one or created an exception, you can create a new exception like any other class. Then you simply throw that Exception using the throw-Keyword. For example: ArgumentOutOfRangeException e = new ArgumentOutOfRangeException(); e.Message = "Value must be within 1 and 100"; throw e;or

ArgumentOutOfRangeException e = new ArgumentOutOfRangeException ("Value must be within 1 and 100"); throw e;or throw new ArgumentOutOfRangeException ("Value must be within 1 and 100");[edit]Performance As previously stated, exception handling comes with a performance penalty. Using a HRESULT or a similar special return value is more efficient but inflexible when it comes to management, debugging, or reuse of the code. Exception handling in a managed runtime environment like the .NET or Java runtimes is more efficient that in an unmanaged environment like C++; because, the C++ Compiler has to write bookkeeping code (i.e. to track objects on the heap), whereas in a managed environment much of this bookkeeping code is implicit (i.e. garbage collection). The exact overhead for Exception handling in .NET is hard to predict, because it depends how the compiler on the target platform implements it. Some compilers are using lookup tables, others generate special methods for this task. When it comes to performance tests you should do them on the target platform. In Microsoft Windows, you can use PerfMon.exe, or the System Monitor ActiveX control. When using PerfMon, you select .Net CLR Exceptions as Performance Object and then select the statistics which you are most interrested in. Unhandled Exceptions Unhandeled Exception Dialog Visual Studio 2005 Exceptions Handling Visual Studio 2005 Exceptions DialogIf a exception occurs the CLR traverses up the call stack looking for a matching catch expression. If the CLR doen't finds a matching one, or the Execption gets rethrown eachtime, the Exception bubbles out of the Main() method. In that case Windows handels the Exception. First, Windows is searching for a fitting registered debugger like Visual Studio which can handle the Exception. Visual Studio has very powerfully mechanisms, so ie. for a debug-compiled version Visual Studio jumps directly to the place within the source where the Exception has occured. Further Visual Studio 2005 provides mechanisms to look at the current values of all the Variables which provides an immense programmingadvance compared to most other debuggers. Release compiled Version of your Program doesn't include the additional debug-information needed to map the code to the source. This leads to faster execution, but on the one hand you have to debug within IL. At best it is possible to find the right function within the source, based on the information within the exception (Exception.StackTrace). Also the mapping of the value of the variables gets lost if they are not stored within the exception too (remember Exception.ParamName and Exception.ActualValue). The debugger of Microsofts Visual Studio 2005 offers special exception handling support. The Dialog providing the settings for this can be found in Debug/Exceptions from the Menubar. A detailed description can be found within the documentation of Visual Studio. Logging Exceptions You can log exceptions with System.Diagnostics.EventLog if the user uses Windows 2k/XP/2003/Vista. A very good thing when working with public available versions of your program is to set up a server running a public available EventLog, or - on Unix Systems - a special developed WebService to whitch you can report. On uncritical Exceptions you can also present the user a special Window providing text-fields to give additional information (E-Mail Address for contact; Information about the user has done with your Application; etc. - but don't ask for things like the used operating system; figure it out by code where possible). At least it is a much smarter approach than providing just a E-Mail Address or a Webforum, as most developers do, because the error-report is more problem oriented and goes directly to the responsible programmer. If you want to do remote logging let the user decide if she really wants to send the report or not.

Important: It is not possible to create a new window when there is ie. a out-of-memory Exception. If you try it you will get a new out-of-memory Exception, trying to create a new window, creating a new Exception.... This can cause a hangup of the operating-system. Exception policies It is also possible to register an Event Handler for unhandled exceptions. The code below gives an example, how this might look like. The Example works also within threads, so you don't really have to terminate the whole application which can give you the possibility to recover, make an failure report, and maybe respawn the thread. using System; using System.Diagnostics; using System.Windows.Forms; class Application { static void Main() { // Register an Event Handler whitch // handeles the unhandeled Exception AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler (OnUnhandledExceptionPolicy); try { // Application code comes here } finally { // Finalization code comes here } } static void OnUnhandledExceptionPolicy (Object Sender, UnhandledExceptionEventArgs e) { String InformationForLogging; Exception ex = e.ExceptionObject as Exception; if (ex != null) { // The unhandled Exception is CLS compliant // Extract the Information you want to know InformationForLogging = ex.ToString(); } else { // The unhandeled Exception is not CLS compliant // You can only handle this Exception as Object InformationForLogging = String.Format( "Type: {0}{2}String: {1}", e.ExceptionObject.GetType(), e.ExceptionObject.ToString(), Environment.NewLine) } #if DEBUG if (!e.IsTerminating)

{

// Exception occurred in a thread pool or finalizer thread // Debugger launches only explicitly } else { // Exception occurred in managed thread // Debugger will also launch when not launched explicitly } // explicitly launch the debugger (Visual Studio) Debugger.Launch(); #else // This is a final release; // logging is done to Syslog and over the Web if possible // Debugger is mostly not available if (!e.IsTerminating) { // Exception occurred in a thread pool or finalizer thread // Application keeps open } else { // Exception occurred in managed thread // Application is closing, so you should log now } #endif } }Controlling CLR unhandled Exception behavior When a managed thread throws a unhandled Exception, the CLR looks into the registry for the kind of debugging. The Registry Key for this is named DbgJITDebugLaunchSetting and can be found in HKEY_LOCAL_MACHINE\Software\Microsoft\.NetFramework\. DbgJITDebugLaunchSetting Value Behavior 0 Displays a dialog asking the user for debugging. If the user chooses to do not, the UnhandledException gets thrown within the AppDomain. If there is no EventHandler for this the CLR displays the Stacktrace. In the case of a CUI-Application (Console), the Stacktrace will get shown on the console. A GUI-Application (WinForms) shows the Stacktrace within a new window. If the user chooses to debug, the CLR looks for the Key DbgManagedDebuger with can be found also in HKEY_LOCAL_MACHINE\Software\Microsoft\.NetFramework\ and starts this debugger. 1 No dialog box is presented do the user. The UnhandledException gets thrown immediately. 2 No dialog box is presented do the user. The CLR starts the debugger. Next to the settings for the debugger in the registry it is also possible to enable or disable an JIT-Debugger by setting jitDebugging within the applications .config file. Unhandled exceptions in different application types Where and how the output of an unhandeled Exception occurs depends on the application type. There are Console Applications (CUI), WinForms Applications (GUI; including DirectX), ASP.Net Applications, and ASP.Net WebServices. Console Event Handling of Console Applications are the easiest to understand, because there is no special Handling by the CLR. The Exception is leaving the Applications Thread if not caught. The CLR opens a window asking for

debug or exit the application. If the user chooses to debug, the debugger starts. If the user chooses to close, the Application exits and the Exception is serialized and written to the console. Windows Forms In a Windows Forms application, the Run-method of the System.Windows.Forms.Application-Class runs a loop within a new thread. This loop dispatches messages of the type System.Windows.Forms.NativeWindow which contains a try/catch block. Within the try-block of this, Microsoft Windows WndProc-Method is called to create the Window. The catch block of a Window calls the virtual OnThreadException-Method of the window when a CLRExcception occurs. In the case of a control this method calls the OnThreadException-Method from the Application. By default this calls a Window giving the user the possibility to continue or quit the application. If the user continues the application will be in an undefinded state, so he should save his work when possible at best in a new file to avoid corruption of the original file - and restart the application. It is possible to override this window by providing an event handler of type System.Threading.ThreadExceptionEventHandler and registering it for the ThreadException-Event of the Application. Because WindowsForms handle only CLR-Exceptions you might want to create also another ThreadExceptionEventHandler for this and register it for the UnhandeledException-Event of the Application. ASP.Net Web Forms In ASP.Net Web Forms, ASP.Net itself catches most Exceptions using its own try-block. Therefore it is possible to register a callback method using the Error-Event of System.Web.UI.TemplateControl. The TemplateControl-Class itself is the base class of System.Web.UI.Page and System.Web.UI.UserControl, so each Page and Control exposes this Event too. On the other hand it is possible to receive notifications about unhandeled exceptions for a page by registering a callback method. You can register this method Application wide within the Error-Property of the System.Web.Application-Class. Also, ASP.Net offers options to create a dump about the Exception to a Webpage. ASP.Net Web services Web services have also a easy way of handling Exceptions. ASP.Net catches the Exception and throws a new System.Web.Services.Protocols.SoapException. This SoapException is serialized to XML, representing a SOAPFault. This gets understood by other SOAP Clients independently of the Platform or the Programming Environment. If the client is a .NET Framework application the SOAP-Fault is deserialized into a SoapException and thrown at the place where the WebService-Call occurred. This Exception can then get handled like any other exception. Fields and Properties Fields Fields in a class are used to hold data. Fields can be marked as public, private, protected, internal, or protected internal. A field can optionally be declared static. A field can be declared readonly. A read-only field can only be assigned a value during initialization or in a constructor. A field can be given an initial value by using the assignment operator when the field is declared. public class Car { public string make = "Ford";

}Fields are initialized immediately before the constructor for the object instance is called, so if the constructor assigns the value of a field, it will overwrite any value given during field declaration. public class Car { public string make = "Ford"; public Car() { make = "Alfa"; } }These examples use fields that are public, but this is not recommended in practice. Fields should generally be private with access to fields given by using properties. Properties Properties allow users to access class variables as if they were accessing member fields directly, while actually implementing that access through a class method. The user wants direct access to the variables of the object and does not want to work with methods. The class designer, however, wants to hide the internal variables of his class in class members, and provide indirect access through a method. By decoupling the class variables from the methods that access those variables, the designer is free to change the internal state of the object as needed. Coding properties The code below shows how to create a private variable with its associated properties. // private member variables private int hour; // create a property public int Hour { get { return hour; } set { hour = value; } }You then access the properties in the following manner: // Get the current value of hour to local variable iHour int iHour = aClass.Hour; // Increment iHour iHour++; // Write iHour back to hour aClass.Hour = iHour; Properties in C# 2.0 In C# 2.0 you can set the accessibility of get and set. The code below shows how to create a private variable with an internal set and public get. The Hour property can now only be set from code in the same module (dll), but can be accessed by all code that uses the module (dll) that contains the class. // private member variables private int hour; // create a property public int Hour

{ }

get { return hour; } internal set { hour = value; }

Asymmetric Accessor Accessibility The get and set portions of a property or indexer are called accessors. By default these accessors have the same visibility, or access level: that of the property or indexer to which they belong. For more information, see accessibility levels. However, it is sometimes useful to restrict access to one of these accessors. Typically, this involves restricting the accessibility of the set accessor, while keeping the get accessor publicly accessible. For example: private string name = "Hello"; public string Name { get { return name; } protected set { name = value; } } In this example, a property called Name defines a get and set accessor. The get accessor receives the accessibility level of the property itself, public in this case, while the set accessor is explicitly restricted by applying the protected access modifier to the accessor itself. Restrictions on Access Modifiers on Accessors Using the accessor modifiers on properties or indexers is subject to these conditions: You cannot use accessor modifiers on an interface or an explicit interface member implementation. You can use accessor modifiers only if the property or indexer has both set and get accessors. In this case, the modifier is permitted on one only of the two accessors. If the property or indexer has an override modifier, the accessor modifier must match the accessor of the overridden accessor, if any. The accessibility level on the accessor must be more restrictive than the accessibility level on the property or indexer itself. Access Modifiers on Overriding Accessors When you override a property or indexer, the overridden accessors must be accessible to the overriding code. Also, the accessibility level of both the property/indexer, and that of the accessors must match the corresponding overridden property/indexer and the accessors. For example: public class Parent { public virtual int TestProperty { // Notice the accessor accessibility level. protected set { }

// No access modifier is used here. get { return 0; } } } public class Kid : Parent { public override int TestProperty { // Use the same accessibility level as in the overridden accessor. protected set { }

}

// Cannot use access modifier here. get { return 0; }

} Implementing Interfaces When you use an accessor to implement an interface, the accessor may not have an access modifier. However, if you implement the interface using one accessor, such as get, the other accessor can have an access modifier, as in the following example: public interface ISomeInterface { int TestProperty { // No access modifier allowed here // because this is an interface. get; } } public class TestClass : ISomeInterface { public int TestProperty { // Cannot use access modifier here because // this is an interface implementation. get { return 10; }

}

// Interface property does not have set accessor, // so access modifier is allowed. protected set { }

} Accessor Accessibility Domain If you use an access modifier on the accessor, the accessibility domain of the accessor is determined by this modifier. If you did not use an access modifier on the accessor, the accessibility domain of the accessor is determined by the accessibility level of the property or indexer. Example The following example contains three classes, BaseClass, DerivedClass, and MainClass. There are two properties on the BaseClass, Name and Id on both classes. The example demonstrates how the property Id on

DerivedClass can be hidden by the property Id on BaseClass when you use a restrictive access modifier such as protected or private. Therefore, when you assign values to this property, the property on the BaseClass class is called instead. Replacing the access modifier by public will make the property accessible. The example also demonstrates that a restrictive access modifier, such as private or protected, on the set accessor of the Name property in DerivedClass prevents access to the accessor and generates an error when you assign to it. public class BaseClass { private string name = "Name-BaseClass"; private string id = "ID-BaseClass"; public string Name { get { return name; } set { } } public string Id { get { return id; } set { } } } public class DerivedClass : BaseClass { private string name = "Name-DerivedClass"; private string id = "ID-DerivedClass"; new public string Name { get { return name; }

}

// Using "protected" would make the set accessor not accessible. set { name = value; }

// Using private on the following property hides it in the Main Class. // Any assignment to the property will use Id in BaseClass. new private string Id { get { return id; } set { id = value; }

}

}

class MainClass { static void Main() { BaseClass b1 = new BaseClass(); DerivedClass d1 = new DerivedClass(); b1.Name = "Mary"; d1.Name = "John"; b1.Id = "Mary123"; d1.Id = "John123"; // The BaseClass.Id property is called. System.Console.WriteLine("Base: {0}, {1}", b1.Name, b1.Id); System.Console.WriteLine("Derived: {0}, {1}", d1.Name, d1.Id); // Keep the console window open in debug mode. System.Console.WriteLine("Press any key to exit."); System.Console.ReadKey(); } } /* Output: Base: Name-BaseClass, ID-BaseClass Derived: John, ID-BaseClass */ Fields A field is a variable of any type that is declared directly in a class or struct. Fields are members of their containing type. A class or struct may have instance fields or static fields or both. Instance fields are specific to an instance of a type. If you have a class T, with an instance field F, you can create two objects of type T, and modify the value of F in each object without affecting the value in the other object. By contrast, a static field belongs to the class itself, and is shared among all instances of that class. Changes made from instance A will be visibly immediately to instances B and C if they access the field. Generally, you should use fields only for variables that have private or protected accessibility. Data that your class exposes to client code should be provided through methods, properties and indexers. By using these constructs for indirect access to internal fields, you can guard against invalid input values. A private field that stores the data exposed by a public property is called a backing store or backing field. Fields typically store the data that must be accessible to more than one class method and must be stored for longer than the lifetime of any single method. For example, a class that represents a calendar date might have three integer fields: one for the month, one for the day, and one for the year. Variables that are not used outside the scope of a single method should be declared as local variables within the method body itself. Fields are declared in the class block by specifying the access level of the field, followed by the type of the field, followed by the name of the field. For example: public class CalendarEntry { // private field

private DateTime date; // public field (Generally not recommended) public string day; // Public property exposes date field safely. public DateTime Date { get { return date; } set { if(value.Year > 1980 || value.Year <= 2008) { date = value; } else throw new ArgumentOutOfRangeException(); } } // Public method also exposes date field safely. public void SetDate(string dateString) { DateTime dt = Convert.ToDateTime(dateString);

}

if (dt.Year > 1980 || dt.Year <= 2008) { date = dt; } else throw new ArgumentOutOfRangeException();

public TimeSpan GetTimeSpan(string dateString) { DateTime dt = Convert.ToDateTime(dateString); if (dt != null && dt.Ticks < date.Ticks) { return date - dt; } else throw new ArgumentOutOfRangeException(); }

}

To access a field in an object, add a period after the object name, followed by the name of the field, as in objectname.fieldname. For example: CalendarEntry birthday = new CalendarEntry(); birthday.day = "Saturday";

A field can be given an initial value by using the assignment operator when the field is declared. To automatically assign the day field to "Monday", for example, you would declare day as in the following example: public class CalendarDateWithInitialization { public string day = "Monday"; //... } Fields are initialized immediately before the constructor for the object instance is called. If the constructor assigns the value of a field, it will overwrite any value given during field declaration. For more information, see Using Constructors (C# Programming Guide). Note: A field initializer cannot refer to other instance fields. Fields can be marked as public, private, protected, internal, or protected internal. These access modifiers define how users of the class can access the fields. For more information, see Access Modifiers (C# Programming Guide). A field can optionally be declared static. This makes the field available to callers at any time, even if no instance of the class exists. For more information, see Static Classes and Static Class Members (C# Programming Guide). A field can be declared readonly. A read-only field can only be assigned a value during initialization or in a constructor. A static readonly field is very similar to a constant, except that the C# compiler does not have access to the value of a static read-only field at compile time, only at run time Generic Lists List class List is the most useful collection. It is basically an array that can change size dynamically. Since it is a generic collection, it is also type safe. Code Examples Add items to a list List numbers = new List(); numbers.Add( 1 ); numbers.Add( 2 ); numbers.Add( 3 );Does a list contain an item if( numbers.Contains( 3 ){ //... }Remove items from a list numbers.Remove( 1 ); numbers.Remove( 2 ); numbers.Remove( 3 );Remove the first 3 items in a List // When an item is removed all, // items following it are moved to fill the gap // So in order to remove the first 3 items, // Remove from the first item 3 times numbers.RemoveAt( 0 );

numbers.RemoveAt( 0 ); numbers.RemoveAt( 0 );[edit]List.Enumerator structure The List.Enumerator implements the IEnumerator interface for a generic List. See IEnumerator and IEnumerator. Generic Queue FIFO The Queue class allows the implementation of a FIFO (First-In-First-Out) storage system

Due to Queue being a collection it can easily be simulated using a List. This is handy to remember so that if find yourself trying to implement such a system just remember that one already exists! Generic.Queue vs Queue The Collections.Generic.Queue should always be chosen over the Collections.Queue class to promote type safety. However, their basic operation is identical in every area apart from when using an enumerator. Usage of Generic Queue System.InvalidOperationException thrown if no check for within bounds. byte data = 42; Queue myQueue = new Queue(); myQueue.Enqueue(data); if (myQueue.Count > 0) //Check within bounds { data = myQueue.Dequeue(); } Simulation of Queue using Generic List Note that by simulating a queue like this means that all elements are open for access and therefore the queue can be abused. System.ArgumentOutOfRangeException thrown if no check for within bounds byte data = 42; List myList = new List(); myList.Add(data); //Enqueue if (myList.Count > 0) //Check within bounds

{

//Dequeue data = myList[0]; myList.RemoveAt(0);

} Enumerator The Enumerator or more precisely the Queue.Enumerator allows simple iteration through the elements of the Queue. Note: To protect the Queue from abuse the enumerator only allows read operations. Unlike the IEnumerator (returned by Collections.Queue) the Queue.Enumerator does not provide a Reset method. The most important thing to remember when using an enumerator is not to modify the Queue once an instance of the enumerator has been created. Therefore the fool-proof way of ensuring this is to stick it inside its own method. using System; using System.Collections.Generic; static void queueEnumeratorEG() { Queue myQueue = new Queue(); myQueue.Enqueue(1); myQueue.Enqueue(2); myQueue.Enqueue(3); myQueue.Enqueue(4); queuePrint(myQueue); myQueue.Dequeue(); myQueue.Dequeue(); }

queuePrint(myQueue);

static void queuePrint(Queue myQueue) { Queue.Enumerator mqEnumerator = myQueue.GetEnumerator(); while (mqEnumerator.MoveNext()) { Console.WriteLine(mqEnumerator.Current.ToString()); } Console.WriteLine(); }The alternative is to use a foreach statement which uses the enumerator behind the scenes. Queue<(Of <(T>)>) Class Represents a first-in, first-out collection of objects. Namespace: System.Collections.Generic Assembly: System (in System.dll) Visual Basic (Declaration) <SerializableAttribute> _ _

Public Class Queue(Of T) _ Implements IEnumerable(Of T), ICollection, IEnumerable Visual Basic (Usage) Dim instance As Queue(Of T) C# [SerializableAttribute] [ComVisibleAttribute(false)] public class Queue : IEnumerable, ICollection, IEnumerable Type Parameters T Specifies the type of elements in the queue. Remarks Queues are useful for storing messages in the order they were received for sequential processing. Objects stored in a Queue<(Of <(T>)>) are inserted at one end and removed from the other. The capacity of a Queue<(Of <(T>)>) is the number of elements the Queue<(Of <(T>)>) can hold. As elements are added to a Queue<(Of <(T>)>), the capacity is automatically increased as required by reallocating the internal array. The capacity can be decreased by calling TrimExcess. Queue<(Of <(T>)>) accepts nullNothingnullptra null reference (Nothing in Visual Basic) as a valid value for reference types and allows duplicate elements. Examples The following code example demonstrates several methods of the Queue<(Of <(T>)>) generic class. The code example creates a queue of strings with default capacity and uses the Enqueue method to queue five strings. The elements of the queue are enumerated, which does not change the state of the queue. The Dequeue method is used to dequeue the first string. The Peek method is used to look at the next item in the queue, and then the Dequeue method is used to dequeue it. The ToArray method is used to create an array and copy the queue elements to it, then the array is passed to the Queue<(Of <(T>)>) constructor that takes IEnumerable<(Of <(T>)>), creating a copy of the queue. The elements of the copy are displayed. An array twice the size of the queue is created, and the CopyTo method is used to copy the array elements beginning at the middle of the array. The Queue<(Of <(T>)>) constructor is used again to create a second copy of the queue containing three null elements at the beginning. The Contains method is used to show that the string "four" is in the first copy of the queue, after which the Clear method clears the copy and the Count property shows that the queue is empty. Visual Basic Imports System Imports System.Collections.Generic Module Example Sub Main Dim numbers As New Queue(Of String) numbers.Enqueue("one") numbers.Enqueue("two") numbers.Enqueue("three") numbers.Enqueue("four")

numbers.Enqueue("five") ' A queue can be enumerated without disturbing its contents. For Each number As String In numbers Console.WriteLine(number) Next Console.WriteLine(vbLf & "Dequeuing '{0}'", numbers.Dequeue()) Console.WriteLine("Peek at next item to dequeue: {0}", _ numbers.Peek()) Console.WriteLine("Dequeuing '{0}'", numbers.Dequeue()) ' Create a copy of the queue, using the ToArray method and the ' constructor that accepts an IEnumerable(Of T). Dim queueCopy As New Queue(Of String)(numbers.ToArray()) Console.WriteLine(vbLf & "Contents of the first copy:") For Each number As String In queueCopy Console.WriteLine(number) Next ' Create an array twice the size of the queue, compensating ' for the fact that Visual Basic allocates an extra array ' element. Copy the elements of the queue, starting at the ' middle of the array. Dim array2((numbers.Count * 2) - 1) As String numbers.CopyTo(array2, numbers.Count) ' Create a second queue, using the constructor that accepts an ' IEnumerable(Of T). Dim queueCopy2 As New Queue(Of String)(array2) Console.WriteLine(vbLf & _ "Contents of the second copy, with duplicates and nulls:") For Each number As String In queueCopy2 Console.WriteLine(number) Next Console.WriteLine(vbLf & "queueCopy.Contains(""four"") = {0}", _ queueCopy.Contains("four")) Console.WriteLine(vbLf & "queueCopy.Clear()") queueCopy.Clear() Console.WriteLine(vbLf & "queueCopy.Count = {0}", _ queueCopy.Count) End Sub End Module ' This code example produces the following output: ' 'one 'two 'three 'four 'five ' 'Dequeuing 'one'

'Peek at next item to dequeue: two ' 'Dequeuing 'two' ' 'Contents of the copy: 'three 'four 'five ' 'Contents of the second copy, with duplicates and nulls: ' ' ' 'three 'four 'five ' 'queueCopy.Contains("four") = True ' 'queueCopy.Clear() ' 'queueCopy.Count = 0 C# using System; using System.Collections.Generic; class Example { public static void Main() { Queue<string> numbers = new Queue<string>(); numbers.Enqueue("one"); numbers.Enqueue("two"); numbers.Enqueue("three"); numbers.Enqueue("four"); numbers.Enqueue("five"); // A queue can be enumerated without disturbing its contents. foreach( string number in numbers ) { Console.WriteLine(number); } Console.WriteLine("\nDequeuing '{0}'", numbers.Dequeue()); Console.WriteLine("Peek at next item to dequeue: {0}", numbers.Peek()); Console.WriteLine("Dequeuing '{0}'", numbers.Dequeue()); // Create a copy of the queue, using the ToArray method and the // constructor that accepts an IEnumerable. Queue<string> queueCopy = new Queue<string>(numbers.ToArray()); Console.WriteLine("\nContents of the first copy:"); foreach( string number in queueCopy ) { Console.WriteLine(number);

} // Create an array twice the size of the queue and copy the // elements of the queue, starting at the middle of the // array. string[] array2 = new string[numbers.Count * 2]; numbers.CopyTo(array2, numbers.Count); // Create a second queue, using the constructor that accepts an // IEnumerable(Of T). Queue<string> queueCopy2 = new Queue<string>(array2); Console.WriteLine("\nContents of the second copy, with duplicates and nulls:"); foreach( string number in queueCopy2 ) { Console.WriteLine(number); } Console.WriteLine("\nqueueCopy.Contains(\"four\") = {0}", queueCopy.Contains("four")); Console.WriteLine("\nqueueCopy.Clear()"); queueCopy.Clear(); Console.WriteLine("\nqueueCopy.Count = {0}", queueCopy.Count); }

}

/* This code example produces the following output: one two three four five Dequeuing 'one' Peek at next item to dequeue: two Dequeuing 'two' Contents of the copy: three four five Contents of the second copy, with duplicates and nulls: three four five queueCopy.Contains("four") = True queueCopy.Clear() queueCopy.Count = 0 */

Inheritance Hierarchy System..::.Object System.Collections.Generic..::.Queue<(Of <(T>)>) Thread Safety Public static (Shared in Visual Basic) members of this type are thread safe. Any instance members are not guaranteed to be thread safe. A Queue<(Of <(T>)>) can support multiple readers concurrently, as long as the collection is not modified. Even so, enumerating through a collection is intrinsically not a thread-safe procedure. To guarantee thread safety during enumeration, you can lock the collection during the entire enumeration. To allow the collection to be accessed by multiple threads for reading and writing, you must implement your own synchronization. Queue<(Of <(T>)>)..::.GetEnumerator Method Returns an enumerator that iterates through the Queue<(Of <(T>)>). Namespace: System.Collections.Generic Assembly: System (in System.dll) Syntax Visual Basic (Declaration) Public Function GetEnumerator As Queue<(Of <(T>)>)..::.Enumerator Visual Basic (Usage) Dim instance As Queue Dim returnValue As Queue<(Of <(T>)>)..::.Enumerator returnValue = instance.GetEnumerator() C# public Queue<(Of <(T>)>)..::.Enumerator GetEnumerator() Return Value Type: System.Collections.Generic..::.Queue<(Of <(T>)>)..::.Enumerator An Queue<(Of <(T>)>)..::.Enumerator for the Queue<(Of <(T>)>). Remarks The foreach statement of the C# language (for each in C++, For Each in Visual Basic) hides the complexity of the enumerators. Therefore, using foreach is recommended, instead of directly manipulating the enumerator. Enumerators can be used to read the data in the collection, but they cannot be used to modify the underlying collection. Initially, the enumerator is positioned before the first element in the collection. At this position, Current is undefined. Therefore, you must call MoveNext to advance the enumerator to the first element of the collection before reading the value of Current. Current returns the same object until MoveNext is called. MoveNext sets Current to the next element. If MoveNext passes the end of the collection, the enumerator is positioned after the last element in the collection and MoveNext returns false. When the enumerator is at this position, subsequent calls to MoveNext also return false. If the last call to MoveNext returned false, Current is undefined. You cannot set Current to the first element of the collection again; you must create a new enumerator instance instead. An enumerator remains valid as long as the collection remains unchanged. If changes are made to the collection, such as adding, modifying, or deleting elements, the enumerator is irrecoverably invalidated and its behavior is undefined. The enumerator does not have exclusive access to the collection; therefore, enumerating through a collection is intrinsically not a thread-safe procedure. To guarantee thread safety during enumeration, you can lock the

collection during the entire enumeration. To allow the collection to be accessed by multiple threads for reading and writing, you must implement your own synchronization. Default implementations of collections in System.Collections.Generic are not synchronized. This method is an O(1) operation. Examples The following code example demonstrates that the Queue<(Of <(T>)>) generic class is enumerable. The foreach statement (For Each in Visual Basic, for each in C++) is used to enumerate the queue. The code example creates a queue of strings with default capacity and uses the Enqueue method to queue five strings. The elements of the queue are enumerated, which does not change the state of the queue. The Dequeue method is used to dequeue the first string. The Peek method is used to look at the next item in the queue, and then the Dequeue method is used to dequeue it. The ToArray method is used to create an array and copy the queue elements to it, then the array is passed to the Queue<(Of <(T>)>) constructor that takes IEnumerable<(Of <(T>)>), creating a copy of the queue. The elements of the copy are displayed. An array twice the size of the queue is created, and the CopyTo method is used to copy the array elements beginning at the middle of the array. The Queue<(Of <(T>)>) constructor is used again to create a second copy of the queue containing three null elements at the beginning. The Contains method is used to show that the string "four" is in the first copy of the queue, after which the Clear method clears the copy and the Count property shows that the queue is empty. Visual Basic Copy Code Imports System Imports System.Collections.Generic Module Example Sub Main Dim numbers As New Queue(Of String) numbers.Enqueue("one") numbers.Enqueue("two") numbers.Enqueue("three") numbers.Enqueue("four") numbers.Enqueue("five") ' A queue can be enumerated without disturbing its contents. For Each number As String In numbers Console.WriteLine(number) Next Console.WriteLine(vbLf & "Dequeuing '{0}'", numbers.Dequeue()) Console.WriteLine("Peek at next item to dequeue: {0}", _ numbers.Peek()) Console.WriteLine("Dequeuing '{0}'", numbers.Dequeue()) ' Create a copy of the queue, using the ToArray method and the ' constructor that accepts an IEnumerable(Of T). Dim queueCopy As New Queue(Of String)(numbers.ToArray()) Console.WriteLine(vbLf & "Contents of the first copy:")

For Each number As String In queueCopy Console.WriteLine(number) Next ' Create an array twice the size of the queue, compensating ' for the fact that Visual Basic allocates an extra array ' element. Copy the elements of the queue, starting at the ' middle of the array. Dim array2((numbers.Count * 2) - 1) As String numbers.CopyTo(array2, numbers.Count) ' Create a second queue, using the constructor that accepts an ' IEnumerable(Of T). Dim queueCopy2 As New Queue(Of String)(array2) Console.WriteLine(vbLf & _ "Contents of the second copy, with duplicates and nulls:") For Each number As String In queueCopy2 Console.WriteLine(number) Next Console.WriteLine(vbLf & "queueCopy.Contains(""four"") = {0}", _ queueCopy.Contains("four")) Console.WriteLine(vbLf & "queueCopy.Clear()") queueCopy.Clear() Console.WriteLine(vbLf & "queueCopy.Count = {0}", _ queueCopy.Count) End Sub End Module ' This code example produces the following output: ' 'one 'two 'three 'four 'five ' 'Dequeuing 'one' 'Peek at next item to dequeue: two ' 'Dequeuing 'two' ' 'Contents of the copy: 'three 'four 'five ' 'Contents of the second copy, with duplicates and nulls: ' ' ' 'three 'four 'five '

'queueCopy.Contains("four") = True ' 'queueCopy.Clear() ' 'queueCopy.Count = 0 C# using System; using System.Collections.Generic; class Example { public static void Main() { Queue<string> numbers = new Queue<string>(); numbers.Enqueue("one"); numbers.Enqueue("two"); numbers.Enqueue("three"); numbers.Enqueue("four"); numbers.Enqueue("five"); // A queue can be enumerated without disturbing its contents. foreach( string number in numbers ) { Console.WriteLine(number); } Console.WriteLine("\nDequeuing '{0}'", numbers.Dequeue()); Console.WriteLine("Peek at next item to dequeue: {0}", numbers.Peek()); Console.WriteLine("Dequeuing '{0}'", numbers.Dequeue()); // Create a copy of the queue, using the ToArray method and the // constructor that accepts an IEnumerable. Queue<string> queueCopy = new Queue<string>(numbers.ToArray()); Console.WriteLine("\nContents of the first copy:"); foreach( string number in queueCopy ) { Console.WriteLine(number); } // Create an array twice the size of the queue and copy the // elements of the queue, starting at the middle of the // array. string[] array2 = new string[numbers.Count * 2]; numbers.CopyTo(array2, numbers.Count); // Create a second queue, using the constructor that accepts an // IEnumerable(Of T). Queue<string> queueCopy2 = new Queue<string>(array2); Console.WriteLine("\nContents of the second copy, with duplicates and nulls:"); foreach( string number in queueCopy2 ) { Console.WriteLine(number); }

Console.WriteLine("\nqueueCopy.Contains(\"four\") = {0}", queueCopy.Contains("four"));

}

Console.WriteLine("\nqueueCopy.Clear()"); queueCopy.Clear(); Console.WriteLine("\nqueueCopy.Count = {0}", queueCopy.Count);

} /* This code example produces the following output: one two three four five Dequeuing 'one' Peek at next item to dequeue: two Dequeuing 'two' Contents of the copy: three four five Contents of the second copy, with duplicates and nulls: three four five queueCopy.Contains("four") = True queueCopy.Clear() queueCopy.Count = 0 */ Generic Stack LIFO The Stack class allows the implementation of a LIFO(Last-In-First-Out) storage system.

Due to Stack being a collection it can easily be simulated using a List. This is handy to remember so that if find yourself trying to implement such a system just remember that one already exists! Generic.Stack vs Stack The Collections.Generic.Stack should always be chosen over the Collections.Stack class to promote type safety. However, their basic operation is identical in every area apart from when using an enumerator. Usage of Generic Stack System.InvalidOperationException thrown if no check for within bounds. byte data = 42; Stack myStack = new Stack(); myStack.Push(data); if (myStack.Count > 0) //Check within bounds { data = myStack.Pop(); }[edit]Simulation of Generic Stack using Generic List Note that by simulating a stack like this means that all elements are open for access and therefore the stack can be abused. System.ArgumentOutOfRangeException thrown if no check for within bounds byte data = 42; List myList = new List(); myList.Insert(0, data); //PUSH if (myList.Count > 0) //Check within bounds { //POP data = myList[0]; myList.RemoveAt(0); }[edit]Enumerator The Enumerator or more precisely the Stack.Enumerator allows simple iteration through the elements of the stack. Note: To protect the stack from abuse the enumerator only allows read operations. Unlike the IEnumerator (returned by Collections.Stack) the Stack.Enumerator does not provide a Reset method. The most important thing to remember when using an enumerator is not to modify the stack once an instance of the enumerator has been created. Therefore the fool-proof way of ensuring this is to stick it inside its own method. using System; using System.Collections.Generic; static void stackEnumeratorEG() { Stack myStack = new Stack(); myStack.Push(1); myStack.Push(2); myStack.Push(3); myStack.Push(4);

stackPrint(myStack); myStack.Pop(); myStack.Pop(); }

stackPrint(myStack);

static void stackPrint(Stack myStack) { Stack.Enumerator msEnumerator = myStack.GetEnumerator(); while (msEnumerator.MoveNext()) { Console.WriteLine(msEnumerator.Current.ToString()); } Console.WriteLine(); }The alternative is to use a foreach statement which uses the enumerator behind the scenes. Stack<(Of <(T>)>) Class Represents a variable size last-in-first-out (LIFO) collection of instances of the same arbitrary type. Namespace: System.Collections.Generic Assembly: System (in System.dll) Syntax Visual Basic (Declaration) <SerializableAttribute> _ _ Public Class Stack(Of T) _ Implements IEnumerable(Of T), ICollection, IEnumerable Visual Basic (Usage) Dim instance As Stack(Of T) C# [SerializableAttribute] [ComVisibleAttribute(false)] public class Stack : IEnumerable, ICollection, IEnumerable Type Parameters T Specifies the type of elements in the stack. Remarks Stack<(Of <(T>)>) is implemented as an array. The capacity of a Stack<(Of <(T>)>) is the number of elements the Stack<(Of <(T>)>) can hold. As elements are added to a Stack<(Of <(T>)>), the capacity is automatically increased as required by reallocating the internal array. The capacity can be decreased by calling TrimExcess. If Count is less than the capacity of the stack, Push is an O(1) operation. If the capacity needs to be increased to accommodate the new element, Push becomes an O(n) operation, where n is Count. Pop is an O(1) operation. Stack<(Of <(T>)>) accepts nullNothingnullptra null reference (Nothing in Visual Basic) as a valid value for reference types and allows duplicate elements.

Examples The following code example demonstrates several methods of the Stack<(Of <(T>)>) generic class. The code example creates a stack of strings with default capacity and uses the Push method to push five strings onto the stack. The elements of the stack are enumerated, which does not change the state of the stack. The Pop method is used to pop the first string off the stack. The Peek method is used to look at the next item on the stack, and then the Pop method is used to pop it off. The ToArray method is used to create an array and copy the stack elements to it, then the array is passed to the Stack<(Of <(T>)>) constructor that takes IEnumerable<(Of <(T>)>), creating a copy of the stack with the order of the elements reversed. The elements of the copy are displayed. An array twice the size of the stack is created, and the CopyTo method is used to copy the array elements beginning at the middle of the array. The Stack<(Of <(T>)>) constructor is used again to create a copy of the stack with the order of elements reversed; thus, the three null elements are at the end. The Contains method is used to show that the string "four" is in the first copy of the stack, after which the Clear method clears the copy and the Count property shows that the stack is empty. Visual Basic Copy Code Imports System Imports System.Collections.Generic Module Example Sub Main Dim numbers As New Stack(Of String) numbers.Push("one") numbers.Push("two") numbers.Push("three") numbers.Push("four") numbers.Push("five") ' A stack can be enumerated without disturbing its contents. For Each number As String In numbers Console.WriteLine(number) Next Console.WriteLine(vbLf & "Popping '{0}'", numbers.Pop()) Console.WriteLine("Peek at next item to pop: {0}", _ numbers.Peek()) Console.WriteLine("Popping '{0}'", numbers.Pop()) ' Create another stack, using the ToArray method and the ' constructor that accepts an IEnumerable(Of T). Note that ' the order of items on the new stack is reversed. Dim stack2 As New Stack(Of String)(numbers.ToArray()) Console.WriteLine(vbLf & "Contents of the first copy:") For Each number As String In stack2 Console.WriteLine(number) Next ' Create an array twice the size of the stack, compensating ' for the fact that Visual Basic allocates an extra array ' element. Copy the elements of the stack, starting at the

' middle of the array. Dim array2((numbers.Count * 2) - 1) As String numbers.CopyTo(array2, numbers.Count) ' Create a second stack, using the constructor that accepts an ' IEnumerable(Of T). The elements are reversed, with the null ' elements appearing at the end of the stack when enumerated. Dim stack3 As New Stack(Of String)(array2) Console.WriteLine(vbLf & _ "Contents of the second copy, with duplicates and nulls:") For Each number As String In stack3 Console.WriteLine(number) Next Console.WriteLine(vbLf & "stack2.Contains(""four"") = {0}", _ stack2.Contains("four")) Console.WriteLine(vbLf & "stack2.Clear()") stack2.Clear() Console.WriteLine(vbLf & "stack2.Count = {0}", _ stack2.Count) End Sub End Module ' This code example produces the following output: ' 'five 'four 'three 'two 'one ' 'Popping 'five' 'Peek at next item to pop: four 'Popping 'four' ' 'Contents of the first copy: 'one 'two 'three ' 'Contents of the second copy, with duplicates and nulls: 'one 'two 'three ' ' ' ' 'stack2.Contains("four") = False ' 'stack2.Clear() ' 'stack2.Count = 0 C#

using System; using System.Collections.Generic; class Example { public static void Main() { Stack<string> numbers = new Stack<string>(); numbers.Push("one"); numbers.Push("two"); numbers.Push("three"); numbers.Push("four"); numbers.Push("five"); // A stack can be enumerated without disturbing its contents. foreach( string number in numbers ) { Console.WriteLine(number); } Console.WriteLine("\nPopping '{0}'", numbers.Pop()); Console.WriteLine("Peek at next item to destack: {0}", numbers.Peek()); Console.WriteLine("Popping '{0}'", numbers.Pop()); // Create a copy of the stack, using the ToArray method and the // constructor that accepts an IEnumerable. Stack<string> stack2 = new Stack<string>(numbers.ToArray()); Console.WriteLine("\nContents of the first copy:"); foreach( string number in stack2 ) { Console.WriteLine(number); } // Create an array twice the size of the stack and copy the // elements of the stack, starting at the middle of the // array. string[] array2 = new string[numbers.Count * 2]; numbers.CopyTo(array2, numbers.Count); // Create a second stack, using the constructor that accepts an // IEnumerable(Of T). Stack<string> stack3 = new Stack<string>(array2); Console.WriteLine("\nContents of the second copy, with duplicates and nulls:"); foreach( string number in stack3 ) { Console.WriteLine(number); } Console.WriteLine("\nstack2.Contains(\"four\") = {0}", stack2.Contains("four")); Console.WriteLine("\nstack2.Clear()"); stack2.Clear(); Console.WriteLine("\nstack2.Count = {0}", stack2.Count);

}

}

/* This code example produces the following output: five four three two one Popping 'five' Peek at next item to destack: four Popping 'four' Contents of the first copy: one two three Contents of the second copy, with duplicates and nulls: one two three stack2.Contains("four") = False stack2.Clear() stack2.Count = 0 */ Inheritance Hierarchy System..::.Object System.Collections.Generic..::.Stack<(Of <(T>)>) Thread Safety Public static (Shared in Visual Basic) members of this type are thread safe. Any instance members are not guaranteed to be thread safe. A Stack<(Of <(T>)>) can support multiple readers concurrently, as long as the collection is not modified. Even so, enumerating through a collection is intrinsically not a thread-safe procedure. To guarantee thread safety during enumeration, you can lock the collection during the entire enumeration. To allow the collection to be accessed by multiple threads for reading and writing, you must implement your own synchronization. Stack<(Of <(T>)>)..::.GetEnumerator Method Returns an enumerator for the Stack<(Of <(T>)>). Namespace: System.Collections.Generic Assembly: System (in System.dll) Syntax Visual Basic (Declaration) Public Function GetEnumerator As Stack<(Of <(T>)>)..::.Enumerator Visual Basic (Usage)

Dim instance As Stack Dim returnValue As Stack<(Of <(T>)>)..::.Enumerator returnValue = instance.GetEnumerator() C# public Stack<(Of <(T>)>)..::.Enumerator GetEnumerator() Return Value Type: System.Collections.Generic..::.Stack<(Of <(T>)>)..::.Enumerator An Stack<(Of <(T>)>)..::.Enumerator for the Stack<(Of <(T>)>). Remarks The foreach statement of the C# language (for each in C++, For Each in Visual Basic) hides the complexity of the enumerators. Therefore, using foreach is recommended, instead of directly manipulating the enumerator. Enumerators can be used to read the data in the collection, but they cannot be used to modify the underlying collection. Initially, the enumerator is positioned before the first element in the collection. At this position, Current is undefined. Therefore, you must call MoveNext to advance the enumerator to the first element of the collection before reading the value of Current. Current returns the same object until MoveNext is called. MoveNext sets Current to the next element. If MoveNext passes the end of the collection, the enumerator is positioned after the last element in the collection and MoveNext returns false. When the enumerator is at this position, subsequent calls to MoveNext also return false. If the last call to MoveNext returned false, Current is undefined. You cannot set Current to the first element of the collection again; you must create a new enumerator instance instead. An enumerator remains valid as long as the collection remains unchanged. If changes are made to the collection, such as adding, modifying, or deleting elements, the enumerator is irrecoverably invalidated and its behavior is undefined. The enumerator does not have exclusive access to the collection; therefore, enumerating through a collection is intrinsically not a thread-safe procedure. To guarantee thread safety during enumeration, you can lock the collection during the entire enumeration. To allow the collection to be accessed by multiple threads for reading and writing, you must implement your own synchronization. Default implementations of collections in System.Collections.Generic are not synchronized. This method is an O(1) operation. Examples The following code example demonstrates that the Stack<(Of <(T>)>) generic class is enumerable. The foreach statement (For Each in Visual Basic, for each in C++) is used to enumerate the queue. The code example creates a stack of strings with default capacity and uses the Push method to push five strings onto the stack. The elements of the stack are enumerated, which does not change the state of the stack. The Pop method is used to pop the first string off the stack. The Peek method is used to look at the next item on the stack, and then the Pop method is used to pop it off. The ToArray method is used to create an array and copy the stack elements to it, then the array is passed to the Stack<(Of <(T>)>) constructor that takes IEnumerable<(Of <(T>)>), creating a copy of the stack with the order of the elements reversed. The elements of the copy are displayed.

An array twice the size of the stack is created, and the CopyTo method is used to copy the array elements beginning at the middle of the array. The Stack<(Of <(T>)>) constructor is used again to create a copy of the stack with the order of elements reversed; thus, the three null elements are at the end. The Contains method is used to show that the string "four" is in the first copy of the stack, after which the Clear method clears the copy and the Count property shows that the stack is empty. Visual Basic Copy Code Imports System Imports System.Collections.Generic Module Example Sub Main Dim numbers As New Stack(Of String) numbers.Push("one") numbers.Push("two") numbers.Push("three") numbers.Push("four") numbers.Push("five") ' A stack can be enumerated without disturbing its contents. For Each number As String In numbers Console.WriteLine(number) Next Console.WriteLine(vbLf & "Popping '{0}'", numbers.Pop()) Console.WriteLine("Peek at next item to pop: {0}", _ numbers.Peek()) Console.WriteLine("Popping '{0}'", numbers.Pop()) ' Create another stack, using the ToArray method and the ' constructor that accepts an IEnumerable(Of T). Note that ' the order of items on the new stack is reversed. Dim stack2 As New Stack(Of String)(numbers.ToArray()) Console.WriteLine(vbLf & "Contents of the first copy:") For Each number As String In stack2 Console.WriteLine(number) Next ' Create an array twice the size of the stack, compensating ' for the fact that Visual Basic allocates an extra array ' element. Copy the elements of the stack, starting at the ' middle of the array. Dim array2((numbers.Count * 2) - 1) As String numbers.CopyTo(array2, numbers.Count) ' Create a second stack, using the constructor that accepts an ' IEnumerable(Of T). The elements are reversed, with the null ' elements appearing at the end of the stack when enumerated. Dim stack3 As New Stack(Of String)(array2) Console.WriteLine(vbLf & _ "Contents of the second copy, with duplicates and nulls:") For Each number As String In stack3

Console.WriteLine(number) Next Console.WriteLine(vbLf & "stack2.Contains(""four"") = {0}", _ stack2.Contains("four")) Console.WriteLine(vbLf & "stack2.Clear()") stack2.Clear() Console.WriteLine(vbLf & "stack2.Count = {0}", _ stack2.Count) End Sub End Module ' This code example produces the following output: ' 'five 'four 'three 'two 'one ' 'Popping 'five' 'Peek at next item to pop: four 'Popping 'four' ' 'Contents of the first copy: 'one 'two 'three ' 'Contents of the second copy, with duplicates and nulls: 'one 'two 'three ' ' ' ' 'stack2.Contains("four") = False ' 'stack2.Clear() ' 'stack2.Count = 0 C# using System; using System.Collections.Generic; class Example { public static void Main() { Stack<string> numbers = new Stack<string>(); numbers.Push("one"); numbers.Push("two"); numbers.Push("three"); numbers.Push("four");

numbers.Push("five"); // A stack can be enumerated without disturbing its contents. foreach( string number in numbers ) { Console.WriteLine(number); } Console.WriteLine("\nPopping '{0}'", numbers.Pop()); Console.WriteLine("Peek at next item to destack: {0}", numbers.Peek()); Console.WriteLine("Popping '{0}'", numbers.Pop()); // Create a copy of the stack, using the ToArray method and the // constructor that accepts an IEnumerable. Stack<string> stack2 = new Stack<string>(numbers.ToArray()); Console.WriteLine("\nContents of the first copy:"); foreach( string number in stack2 ) { Console.WriteLine(number); } // Create an array twice the size of the stack and copy the // elements of the stack, starting at the middle of the // array. string[] array2 = new string[numbers.Count * 2]; numbers.CopyTo(array2, numbers.Count); // Create a second stack, using the constructor that accepts an // IEnumerable(Of T). Stack<string> stack3 = new Stack<string>(array2); Console.WriteLine("\nContents of the second copy, with duplicates and nulls:"); foreach( string number in stack3 ) { Console.WriteLine(number); } Console.WriteLine("\nstack2.Contains(\"four\") = {0}", stack2.Contains("four"));

}

Console.WriteLine("\nstack2.Clear()"); stack2.Clear(); Console.WriteLine("\nstack2.Count = {0}", stack2.Count);

} /* This code example produces the following output: five four three two one Popping 'five'

Peek at next item to destack: four Popping 'four' Contents of the first copy: one two three Contents of the second copy, with duplicates and nulls: one two three stack2.Contains("four") = False stack2.Clear() stack2.Count = 0 */ Generic interfaces ICollection IList IDictionary IComparable IComparer IEqualityComparer IEnumerable IEnumerator IEnumerator supports a type safe iteration over a generic collection. It has all the same members as IEnumerator (It "inherits" from IEnumerator), however it also has a Current property of type T. The T Current property allows retrieving the current item in the iteration without requiring a cast from object. When implementing the generic IEnumerator, implement the nongeneric Current property explicitly: public class MyEnumerator : IEnumerator{ // Implement the Generic Current implicitly // so it is always visible public T Current { get{ //... } } // Implement the nonGeneric Current explicitly // so it is only visible with a // nongeneric IEnumertor refererence public object IEnumator.Current { get{ //... } } //... }

Generic types Generics is the implementation of parametric polymorphism. Using parametric polymorphism, a method or data type can be written generically so that it can deal equally well with objects of various types. It is a way to make a language more expressible, while still maintaining full static type-safety. Why use generics? There are mainly two reasons to use generics. These are: Performance – Collections that store objects use Boxing and Unboxing on data types. This uses a significant amount of overhead, which can give a performance hit. By using generics instead, this performance hit is removed. Type Safety – There is no strong type information at compile type as to what is stored in the collection. To understand these better, a simple example which does not use generics can be used. Consider the following class; public class Stack { object[] store; int size; public void Push(object obj) {...} public object Pop() {...} }In order to use this class you can push any object onto the Stack, however when retrieving an object, an explicit cast is required. Stack s = new Stack(); s.Push(28); int j = (int)s.Pop(); //unboxing with explicit int casting Such Boxing and Unboxing operations add performance overhead since they involve dynamic memory allocations and run-time type checks. Now imagine what would happen if you pushed a string on the Stack as in the following code; Stack s = new Stack(); s.Push("Hello World!"); // pushing the string int i = (int)s.Pop(); // run-time exception will be thrown at this point The code will compile, however the problem will not become visible until the code is executed, at which point an InvalidCastException will be thrown. Generic equivalent If the Stack class above was of a generic type, there would be a compile-time error when pushing the string onto the Stack. The generic version of the Stack class looks like the following code; public class Stack { // Items are of type T, which is known when you create the object T[] items; int count; public void Push(T item) {...} // The type of the method Pop will be decided when you create the object public T Pop() {...} }T is the type for the parameter. Within class you can use T as if it were a type, this could be anything from a simple data-type such as int to a complex object such as Car. In the following example, string is given as the type argument for T: Stack<string> s = new Stack<string>(); s.Push("Hello World!");

string str = s.Pop();The Stack<string> type is called a constructed type. In the Stack<string> type, every occurrence of T is replaced with the type argument string. The Push and Pop methods of a Stack<string> operate on string values, making it a compile-time error to push values of other types onto the Stack, and eliminating the need to explicitly cast values back to their original type when they are retrieved. You can use parameterization not only for classes but also for interfaces, structs, methods and delegates. interface IComparable struct HashBucket static void Sort (T[] arr) delegate void Action (T arg) Terminology There are several terms that are used when talking about generics, so it is worth mentioning them here so that when reading other documents, a better understanding can be obtained. Type parameters A type parameter refers to the parameter that is used in the definition of the generic type. In the generic version of the Stack class above, the class accepts one type parameter, T. Type arguments A type argument refers to the type you specify to use in place of the type parameter. In the following code segment, string is the type argument. Stack<string> s = new Stack<string>();[edit]Open types Instead of referring to this as a class, generics consider the Stack as an "open type". The term "open" is meant to convey the idea that the type is not fully defined and is "open" to taking on multiple real representations. Constructed types A constructed type represents an instance of an open type. To create a constructed type from the open Stack type, use the following code: Stack<string> s;Or Stack<string> s = new Stack<string>();[edit]Open constructed type An open constructed type is created when at least one type argument is left unspecified, the parameter is still open to run-time definition. Consider the following type declaration: public class LinkedList { ... }The following are all open constructed types: LinkedList myList_1; LinkedList myList_2; LinkedList myList_3;[edit]Closed constructed type A closed constructed type is created by specifying all of the type arguments, therefore they are not open to run-time definition. Consider the following type declaration: public class LinkedList { ... }The following are all closed constructed types: LinkedList myList_1; LinkedList myList_2; LinkedList myList_3; Constraints on type parameters

Constraints are used to restrict a generic class to the kinds of types that client code can use for type arguments. If code attempts to instantiate the class with a type that is not allowed by a constraint, then this will result in a compile-time error. Constraints are specified using the where keyword. The following table lists the five types of constraints: Constraint Description where T : struct The type argument, T, must be any value type except Nullable. where T : class The type argument, T, must be a reference type, including any class, interface, delegate, or array type. where T : new() The type argument, T, must have a public no-argument constructor. When used in conjunction with other constraints, the new() constraint must be specified last. where T : The type argument, T, must be or derive from the specified base class. where T : The type argument, T, must be or implement the specified interface. Multiple interface constraints can be specified. The constraining interface can also be generic. where T : U The type argument, T, must be or derive from the argument supplied for U. This is called a naked type constraint. Generic classes Generic classes encapsulate operations that are not specific to a particular data type. Generic classes can be the base class to other classes, and can therefore define any number of virtual or abstract methods. Any derived type must abide by rules to ensure that the nature of the generic abstraction flows through to it. If a non-generic class extends a generic class, the derived class must specify a type parameter: // Generic list class. public class GenericList { private List myList = new List(); } // Derived type specifies the type parameter. public class MyStringList : GenericList<string> { }If a generic base class defines generic virtual or abstract methods, the derived type must override the generic methods using the specified type parameter: // Generic class with virtual method. public class GenericList { private List myList = new List(); public virtual void PrintList(T data) { } } public class MyStringList : GenericList<string> { // Derived method must substitute the type parameter public override void PrintList(string data) { } }A generic derived type may reuse the type placeholder in its definition. Any constraints placed on the base class must be honoured by the derived type: // Default constructor constraint. public class GenericList where T : new() { private List myList = new List();

}

public virtual void PrintList(T data) { }

// Derived type must honour constraint. public class MyReadOnlyList : GenericList where T : new() { public override void PrintList(T data) { } } Generic interfaces With generic classes it is preferable to use generic interfaces, such as IComparable rather than IComparable, in order to avoid Boxing and Unboxing operations on value types. When an interface is specified as a constraint on a type parameter, only types that implement the interface can be used. For example: public class SortedList : GenericList where T : System.IComparable { ... } Defining a generic interface You may define generic interfaces similar to generic classes (including constraints): // Standard Interface public interface IPrint { void Print(); } // Generic Interface public interface MyGenericInterface where T : IPrint { void Run(T t); } // Class that implements standard Interface public class MyPrinter : IPrint { public void Print() { Console.WriteLine("hello"); } } // Class that implements Generic Interface public class Print2 : MyGenericInterface<MyPrinter> { public void Run(MyPrinter t) { t.Print(); } } // Generic Class that implements Generic Interface with contraints public class PrintDemo : MyGenericInterface where T : IPrint

{

public void Run(T t) { t.Print(); } }The .NET Framework has generic versions of all of the common interfaces. Generic delegates Suppose that we want a delegate that can update an item, but we are not sure what item is going to be updated. In this scenario, making the delegate generic is the best option. In order to explain this concept, the following code is based on an example from Tod Golding in .Net 2.0 Generics. Imagine if you will that we are creating a piece of software that works with animals, namely cats and dogs. So here are two classes with some properties and a ToString() method: public class Cat { private string m_name; public string Name { get { return m_name; } set { m_name = value; } } private int m_age; public int Age { get { return m_age; } set { m_age = value; } } public Cat(string name, int age) { m_name = name; m_age = age; } public override string ToString() { return string.Format("The Cat named {0} is {1} years old", m_name.ToString(), m_age.ToString()); } } public class Dog { private string m_name; public string Name { get { return m_name; } set { m_name = value; } } private double m_age; public double Age { get { return m_age; }

}

set { m_age = value; }

public Dog(string name, double age) { m_name = name; m_age = age; } public override string ToString() { return string.Format("The Dog named {0} is {1} years old", m_name.ToString(), m_age.ToString()); } }We want a delegate that can update the age of either a cat or a dog. public delegate void UpdateAnimal(T value);As we will have many animals, a collection would be a good thing to have, and again to save on overhead and to give type safety, a generic collection would be best. public class Animals : List { public void UpdateAnimals(UpdateAnimal updater) { List.Enumerator items = GetEnumerator();

}

while (items.MoveNext()) { updater(items.Current); }

public void Print() { List.Enumerator items = GetEnumerator(); while (items.MoveNext()) { Console.WriteLine(items.Current.ToString()); }

} }Finally, we need a couple of methods to be called by the delegate to update each of the classes, and some code to test them. class Program { static void Main(string[] args) { // Create Lists Animals catList = new Animals(); catList.Add(new Cat("Tinkerbelle", 6)); catList.Add(new Cat("Felix", 3)); catList.Add(new Cat("Whiskers", 10)); catList.Add(new Cat("Tailz", 14)); Animals dogList = new Animals(); dogList.Add(new Dog("Rufus", 12.1)); dogList.Add(new Dog("Peeps", 3.2));

dogList.Add(new Dog("Hairy McClary", 6.3)); // Cats catList.Print(); Console.WriteLine("---------------------------"); catList.UpdateAnimals(new UpdateAnimal(UpdateCatAge)); catList.Print(); Console.WriteLine("==========================="); // Dogs dogList.Print(); Console.WriteLine("---------------------------"); dogList.UpdateAnimals(new UpdateAnimal(UpdateDogAge)); dogList.Print(); } public static void UpdateCatAge(Cat cat) { cat.Age += 1; } public static void UpdateDogAge(Dog dog) { dog.Age += 0.1; }

} This gives the output:

Benefits of Generics Generics provide the solution to a limitation in earlier versions of the common language runtime and the C# language in which generalization is accomplished by casting types to and from the universal base type Object. By creating a generic class, you can create a collection that is type-safe at compile-time.

The limitations of using non-generic collection classes can be demonstrated by writing a short program that uses the ArrayList collection class from the .NET Framework class library. ArrayList is a highly convenient collection class that can be used without modification to store any reference or value type. C# // The .NET Framework 1.1 way to create a list: System.Collections.ArrayList list1 = new System.Collections.ArrayList(); list1.Add(3); list1.Add(105); System.Collections.ArrayList list2 = new System.Collections.ArrayList(); list2.Add("It is raining in Redmond."); list2.Add("It is snowing in the mountains."); But this convenience comes at a cost. Any reference or value type that is added to an ArrayList is implicitly upcast to Object. If the items are value types, they must be boxed when they are added to the list, and unboxed when they are retrieved. Both the casting and the boxing and unboxing operations decrease performance; the effect of boxing and unboxing can be very significant in scenarios where you must iterate over large collections. The other limitation is lack of compile-time type checking; because an ArrayList casts everything to Object, there is no way at compile-time to prevent client code from doing something such as this: C# System.Collections.ArrayList list = new System.Collections.ArrayList(); // Add an integer to the list. list.Add(3); // Add a string to the list. This will compile, but may cause an error later. list.Add("It is raining in Redmond."); int t = 0; // This causes an InvalidCastException to be returned. foreach (int x in list) { t += x; } Although perfectly acceptable and sometimes intentional if you are creating a heterogeneous collection, combining strings and ints in a single ArrayList is more likely to be a programming error, and this error will not be detected until runtime. In versions 1.0 and 1.1 of the C# language, you could avoid the dangers of generalized code in the .NET Framework base class library collection classes only by writing your own type specific collections. Of course, because such a class is not reusable for more than one data type, you lose the benefits of generalization, and you have to rewrite the class for each type that will be stored. What ArrayList and other similar classes really need is a way for client code to specify, on a per-instance basis, the particular data type that they intend to use. That would eliminate the need for the upcast to T:System.Object and would also make it possible for the compiler to do type checking. In other words, ArrayList needs a type parameter. That is exactly what generics provide. In the generic List<(Of <(T>)>) collection, in the N:System.Collections.Generic namespace, the same operation of adding items to the collection resembles this: C# // The .NET Framework 2.0 way to create a list List list1 = new List();

// No boxing, no casting: list1.Add(3); // Compile-time error: // list1.Add("It is raining in Redmond."); For client code, the only added syntax with List<(Of <(T>)>) compared to ArrayList is the type argument in the declaration and instantiation. In return for this slightly more coding complexity, you can create a list that is not only safer than ArrayList, but also significantly faster, especially when the list items are value types. Constraints on Type Parameters When you define a generic class, you can apply restrictions to the kinds of types that client code can use for type arguments when it instantiates your class. If client code tries to instantiate your class by using a type that is not allowed by a constraint, the result is a compile-time error. These restrictions are called constraints. Constraints are specified by using the where contextual keyword. The following table lists the six types of constraints: Constraint where T: struct

Description

The type argument must be a value type. Any value type except Nullable can be specified. where T : class The type argument must be a reference type; this applies also to any class, interface, delegate, or array type. where T : new() The type argument must have a public parameterless constructor. When used together with other constraints, the new() constraint must be specified last. where T : The type argument must be or derive from the specified base class. where T : The type argument must be or implement the specified interface. Multiple interface constraints can be specified. The constraining interface can also be generic. where T : U The type argument supplied for T must be or derive from the argument supplied for U. This is called a naked type constraint. Why Use Constraints If you want to examine an item in a generic list to determine whether it is valid or to compare it to some other item, the compiler must have some guarantee that the operator or method it has to call will be supported by any type argument that might be specified by client code. This guarantee is obtained by applying one or more constraints to your generic class definition. For example, the base class constraint tells the compiler that only objects of this type or derived from this type will be used as type arguments. Once the compiler has this guarantee, it can allow methods of that type to be called in the generic class. Constraints are applied by using the contextual keyword where. The following code example demonstrates the functionality we can add to the GenericList class (in Introduction to Generics (C# Programming Guide)) by applying a base class constraint. C# public class Employee { private string name; private int id; public Employee(string s, int i) { name = s; id = i; } public string Name

{ }

get { return name; } set { name = value; }

public int ID { get { return id; } set { id = value; } } } public class GenericList where T : Employee { private class Node { private Node next; private T data; public Node(T t) { next = null; data = t; } public Node Next { get { return next; } set { next = value; } } public T Data { get { return data; } set { data = value; } } } private Node head; public GenericList() //constructor { head = null; } public void AddHead(T t) { Node n = new Node(t); n.Next = head; head = n; } public IEnumerator GetEnumerator() { Node current = head; while (current != null)

{ }

yield return current.Data; current = current.Next;

} public T FindFirstOccurrence(string s) { Node current = head; T t = null;

}

while (current != null) { //The constraint enables access to the Name property. if (current.Data.Name == s) { t = current.Data; break; } else { current = current.Next; } } return t;

} The constraint enables the generic class to use the Employee.Name property because all items of type T are guaranteed to be either an Employee object or an object that inherits from Employee. Multiple constraints can be applied to the same type parameter, and the constraints themselves can be generic types, as follows: C# class EmployeeList where T : Employee, IEmployee, System.IComparable, new() { // ... } By constraining the type parameter, you increase the number of allowable operations and method calls to those supported by the constraining type and all types in its inheritance hierarchy. Therefore, when you design generic classes or methods, if you will be performing any operation on the generic members beyond simple assignment or calling any methods not supported by System.Object, you will have to apply constraints to the type parameter. When applying the where T : class constraint, avoid the == and != operators on the type parameter because these operators will test for reference identity only, not for value equality. This is the case even if these operators are overloaded in a type that is used as an argument. The following code illustrates this point; the output is false even though the String class overloads the == operator. C# public static void OpTest(T s, T t) where T : class { System.Console.WriteLine(s == t); } static void Main()

{

}

string s1 = "foo"; System.Text.StringBuilder sb = new System.Text.StringBuilder("foo"); string s2 = sb.ToString(); OpTest<string>(s1, s2);

The reason for this behavior is that, at compile time, the compiler only knows that T is a reference type, and therefore must use the default operators that are valid for all reference types. If you must test for value equality, the recommended way is to also apply the where T : IComparable constraint and implement that interface in any class that will be used to construct the generic class. Constraining Multiple Parameters You can apply constraints to multiple parameters, and multiple constraints to a single parameter, as shown in the following example: C# class Base { } class Test where U : struct where T : Base, new() { } Unbounded Type Parameters Type parameters that have no constraints, such as T in public class SampleClass{}, are called unbounded type parameters. Unbounded type parameters have the following rules: The != and == operators cannot be used because there is no guarantee that the concrete type argument will support these operators. They can be converted to and from System.Object or explicitly converted to any interface type. You can compare to null. If an unbounded parameter is compared to null, the comparison will always return false if the type argument is a value type. Naked Type Constraints When a generic type parameter is used as a constraint, it is called a naked type constraint. Naked type constraints are useful when a member function with its own type parameter has to constrain that parameter to the type parameter of the containing type, as shown in the following example: C# class List { void Add(List items) where U : T {/*...*/} } In the previous example, T is a naked type constraint in the context of the Add method, and an unbounded type parameter in the context of the List class. Naked type constraints can also be used in generic class definitions. Note that the naked type constraint must also have been declared within the angle brackets together with any other type parameters: C# //naked type constraint public class SampleClass where T : V { }

The usefulness of naked type constraints with generic classes is very limited because the compiler can assume nothing about a naked type constraint except that it derives from System.Object. Use naked type constraints on generic classes in scenarios in which you want to enforce an inheritance relationship between two type parameters. default Keyword in Generic Code In generic classes and methods, one issue that arises is how to assign a default value to a parameterized type T when you do not know the following in advance: Whether T will be a reference type or a value type. If T is a value type, whether it will be a numeric value or a struct. Given a variable t of a parameterized type T, the statement t = null is only valid if T is a reference type and t = 0 will only work for numeric value types but not for structs. The solution is to use the default keyword, which will return null for reference types and zero for numeric value types. For structs, it will return each member of the struct initialized to zero or null depending on whether they are value or reference types. For nullable value types, default returns a System..::.Nullable<(Of <(T>)>), which is initialized like any struct. The following example from the GenericList class shows how to use the default keyword. For more information, see Generics Overview. C# public class GenericList { private class Node { //...

}

public Node Next; public T Data;

private Node head; //... public T GetNext() { T temp = default(T); Node current = head; if (current != null) { temp = current.Data; current = current.Next; } return temp; }

}

Generics Generics were added to version 2.0 of the C# language and the common language runtime (CLR). Generics introduce to the .NET Framework the concept of type parameters, which make it possible to design classes and methods that defer the specification of one or more types until the class or method is declared and instantiated by client code. For example, by using a generic type parameter T you can write a single class that

other client code can use without incurring the cost or risk of runtime casts or boxing operations, as shown here: C# // Declare the generic class. public class GenericList { void Add(T input) { } } class TestGenericList { private class ExampleClass { } static void Main() { // Declare a list of type int. GenericList list1 = new GenericList(); // Declare a list of type string. GenericList<string> list2 = new GenericList<string>(); // Declare a list of type ExampleClass. GenericList<ExampleClass> list3 = new GenericList<ExampleClass>(); }

}

Generics Overview Use generic types to maximize code reuse, type safety, and performance. The most common use of generics is to create collection classes. The .NET Framework class library contains several new generic collection classes in the System.Collections.Generic namespace. These should be used whenever possible instead of classes such as ArrayList in the System.Collections namespace. You can create your own generic interfaces, classes, methods, events and delegates. Generic classes may be constrained to enable access to methods on particular data types. Information on the types that are used in a generic data type may be obtained at run-time by using reflection. Generics and Reflection Because the Common Language Runtime (CLR) has access to generic type information at run time, you can use reflection to obtain information about generic types in the same way as for non-generic types. For more information, see Generics in the Run Time (C# Programming Guide). In the .NET Framework 2.0 several new members are added to the Type class to enable run-time information for generic types. See the documentation on these classes for more information on how to use these methods and properties. The System.Reflection.Emit namespace also contains new members that support generics. See How to: Define a Generic Type with Reflection Emit. For a list of the invariant conditions for terms used in generic reflection, see the IsGenericType property remarks. System.Type MemberName

Description

IsGenericType

Returns true if a type is generic.

GetGenericArguments

Returns an array of Type objects that represent the type arguments supplied for a constructed type, or the type parameters of a generic type definition. GetGenericTypeDefinition Returns the underlying generic type definition for the current constructed type. GetGenericParameterConstraints Returns an array of Type objects that represent the constraints on the current generic type parameter. ContainsGenericParameters Returns true if the type or any of its enclosing types or methods contain type parameters for which specific types have not been supplied. GenericParameterAttributes Gets a combination of GenericParameterAttributes flags that describe the special constraints of the current generic type parameter. GenericParameter Position For a Type object that represents a type parameter, gets the position of the type parameter in the type parameter list of the generic type definition or generic method definition that declared the type parameter. IsGenericParameter Gets a value that indicates whether the current Type represents a type parameter of a generic type or method definition. IsGenericTypeDefinition Gets a value that indicates whether the current Type represents a generic type definition, from which other generic types can be constructed. Returns true if the type represents the definition of a generic type. DeclaringMethod Returns the generic method that defined the current generic type parameter, or null if the type parameter was not defined by a generic method. MakeGenericType Substitutes the elements of an array of types for the type parameters of the current generic type definition, and returns a Type object representing the resulting constructed type. In addition, new members are added to the MethodInfo class to enable run-time information for generic methods. See the IsGenericMethod property remarks for a list of invariant conditions for terms used to reflect on generic methods. System.Reflection.MemberInfo Member Name IsGenericMethod GetGenericArguments

Description Returns true if a method is generic. Returns an array of Type objects that represent the type arguments of a constructed generic method or the type parameters of a generic method definition. GetGenericMethodDefinition Returns the underlying generic method definition for the current constructed method. ContainsGenericParameters Returns true if the method or any of its enclosing types contain any type parameters for which specific types have not been supplied. IsGenericMethodDefinition Returns true if the current MethodInfo represents the definition of a generic method. MakeGenericMethod Substitutes the elements of an array of types for the type parameters of the current generic method definition, and returns a MethodInfo object representing the resulting constructed method. Generic Classes Generic classes encapsulate operations that are not specific to a particular data type. The most common use for generic classes is with collections like linked lists, hash tables, stacks, queues, trees, and so on. Operations such as adding and removing items from the collection are performed in basically the same way regardless of the type of data being stored. For most scenarios that require collection classes, the recommended approach is to use the ones provided in the .NET Framework class library. For more information about using these classes, see Generics in the .NET Framework Class Library (C# Programming Guide).

Typically, you create generic classes by starting with an existing concrete class, and changing types into type parameters one at a time until you reach the optimal balance of generalization and usability. When creating your own generic classes, important considerations include the following: Which types to generalize into type parameters. As a rule, the more types you can parameterize, the more flexible and reusable your code becomes. However, too much generalization can create code that is difficult for other developers to read or understand. What constraints, if any, to apply to the type parameters (See Constraints on Type Parameters (C# Programming Guide)). A good rule is to apply the maximum constraints possible that will still let you handle the types you must handle. For example, if you know that your generic class is intended for use only with reference types, apply the class constraint. That will prevent unintended use of your class with value types, and will enable you to use the as operator on T, and check for null values. Whether to factor generic behavior into base classes and subclasses. Because generic classes can serve as base classes, the same design considerations apply here as with nongeneric classes. See the rules about inheriting from generic base classes later in this topic. Whether to implement one or more generic interfaces. For example, if you are designing a class that will be used to create items in a generics-based collection, you may have to implement an interface such as IComparable<(Of <(T>)>) where T is the type of your class. For an example of a simple generic class, see Introduction to Generics (C# Programming Guide). The rules for type parameters and constraints have several implications for generic class behavior, especially regarding inheritance and member accessibility. Before proceeding, you should understand some terms. For a generic class Node, client code can reference the class either by specifying a type argument, to create a closed constructed type (Node). Alternatively, it can leave the type parameter unspecified, for example when you specify a generic base class, to create an open constructed type (Node). Generic classes can inherit from concrete, closed constructed, or open constructed base classes: C# class BaseNode { } class BaseNodeGeneric { } // concrete type class NodeConcrete : BaseNode { } //closed constructed type class NodeClosed : BaseNodeGeneric { } //open constructed type class NodeOpen : BaseNodeGeneric { } Non-generic, in other words, concrete, classes can inherit from closed constructed base classes, but not from open constructed classes or naked type parameters because there is no way at run time for client code to supply the type argument required to instantiate the base class. C# //No error class Node1 : BaseNodeGeneric { }

//Generates an error //class Node2 : BaseNodeGeneric {} //Generates an error //class Node3 : T {} Generic classes that inherit from open constructed types must supply type arguments for any base class type parameters that are not shared by the inheriting class, as demonstrated in the following code: C# class BaseNodeMultiple { } //No error class Node4 : BaseNodeMultiple { } //No error class Node5 : BaseNodeMultiple { } //Generates an error //class Node6 : BaseNodeMultiple {} Generic classes that inherit from open constructed types must specify constraints that are a superset of, or imply, the constraints on the base type: C# class NodeItem where T : System.IComparable, new() { } class SpecialNodeItem : NodeItem where T : System.IComparable, new() { } Generic types can use multiple type parameters and constraints, as follows: C# class SuperKeyType where U : System.IComparable where V : new() {} Open constructed and closed constructed types can be used as method parameters: C# void Swap(List list1, List list2) { //code to swap items } void Swap(List list1, List list2) { //code to swap items } If a generic class implements an interface, all instances of that class can be cast to that interface. Generic classes are invariant. In other words, if an input parameter specifies a List, you will get a compile-time error if you try to provide a List. Generic Delegates A delegate can define its own type parameters. Code that references the generic delegate can specify the type argument to create a closed constructed type, just like when instantiating a generic class or calling a generic method, as shown in the following example:

C# public delegate void Del(T item); public static void Notify(int i) { } Del m1 = new Del(Notify); C# version 2.0 has a new feature called method group conversion, which applies to concrete as well as generic delegate types, and enables you to write the previous line with this simplified syntax: C# Del m2 = Notify; Delegates defined within a generic class can use the generic class type parameters in the same way that class methods do. C# class Stack { T[] items; int index; }

public delegate void StackDelegate(T[] items);

Code that references the delegate must specify the type argument of the containing class, as follows: C# private static void DoWork(float[] items) { } public static void TestStack() { Stack s = new Stack(); Stack.StackDelegate d = DoWork; } Generic delegates are especially useful in defining events based on the typical design pattern because the sender argument can be strongly typed and no longer has to be cast to and from Object. C# delegate void StackEventHandler(T sender, U eventArgs); class Stack { public class StackEventArgs : System.EventArgs { } public event StackEventHandler<Stack, StackEventArgs> stackEvent;

}

protected virtual void OnStackChanged(StackEventArgs a) { stackEvent(this, a); }

class SampleClass { public void HandleStackChange(Stack stack, Stack.StackEventArgs args) { } }

public static void Test() { Stack<double> s = new Stack<double>(); SampleClass o = new SampleClass(); s.stackEvent += o.HandleStackChange; } Generic Interfaces It is often useful to define interfaces either for generic collection classes, or for the generic classes that represent items in the collection. The preference for generic classes is to use generic interfaces, such as IComparable<(Of <(T>)>) rather than IComparable, in order to avoid boxing and unboxing operations on value types. The .NET Framework class library defines several generic interfaces for use with the collection classes in the System.Collections.Generic namespace. When an interface is specified as a constraint on a type parameter, only types that implement the interface can be used. The following code example shows a SortedList class that derives from the GenericList class. For more information, see Introduction to Generics (C# Programming Guide). SortedList adds the constraint where T : IComparable. This enables the BubbleSort method in SortedList to use the generic CompareTo method on list elements. In this example, list elements are a simple class, Person, that implements IComparable. C# //Type parameter T in angle brackets. public class GenericList : System.Collections.Generic.IEnumerable { protected Node head; protected Node current = null; // Nested class is also generic on T protected class Node { public Node next; private T data; //T as private member datatype public Node(T t) //T used in non-generic constructor { next = null; data = t; } public Node Next { get { return next; } set { next = value; } }

}

public T Data //T as return type of property { get { return data; } set { data = value; } }

public GenericList() //constructor { head = null; }

public void AddHead(T t) //T as method parameter type { Node n = new Node(t); n.Next = head; head = n; } // Implementation of the iterator public System.Collections.Generic.IEnumerator GetEnumerator() { Node current = head; while (current != null) { yield return current.Data; current = current.Next; } }

}

// IEnumerable inherits from IEnumerable, therefore this class // must implement both the generic and non-generic versions of // GetEnumerator. In most cases, the non-generic method can // simply call the generic method. System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { return GetEnumerator(); }

public class SortedList : GenericList where T : System.IComparable { // A simple, unoptimized sort algorithm that // orders list elements from lowest to highest: public void BubbleSort() { if (null == head || null == head.Next) { return; } bool swapped; do { Node previous = null; Node current = head; swapped = false; while (current.next != null) { // Because we need to call this method, the SortedList // class is constrained on IEnumerable if (current.Data.CompareTo(current.next.Data) > 0) { Node tmp = current.next; current.next = current.next.next; tmp.next = current;

if (previous == null) { head = tmp; } else { previous.next = tmp; } previous = tmp; swapped = true;

} else { previous = current; current = current.next; }

}

} } while (swapped);

} // A simple class that implements IComparable using itself as the // type argument. This is a common design pattern in objects that // are stored in generic lists. public class Person : System.IComparable { string name; int age; public Person(string s, int i) { name = s; age = i; } // This will cause list elements to be sorted on age values. public int CompareTo(Person p) { return age - p.age; } public override string ToString() { return name + ":" + age; } // Must implement Equals. public bool Equals(Person p) { return (this.age == p.age); } } class Program { static void Main()

{

//Declare and instantiate a new generic SortedList class. //Person is the type argument. SortedList list = new SortedList(); //Create name and age values to initialize Person objects. string[] names = new string[] { "Franscoise", "Bill", "Li", "Sandra", "Gunnar", "Alok", "Hiroyuki", "Maria", "Alessandro", "Raul" }; int[] ages = new int[] { 45, 19, 28, 23, 18, 9, 108, 72, 30, 35 }; //Populate the list. for (int x = 0; x < 10; x++) { list.AddHead(new Person(names[x], ages[x])); } //Print out unsorted list. foreach (Person p in list) { System.Console.WriteLine(p.ToString()); } System.Console.WriteLine("Done with unsorted list"); //Sort the list. list.BubbleSort(); //Print out sorted list. foreach (Person p in list) { System.Console.WriteLine(p.ToString()); } System.Console.WriteLine("Done with sorted list");

}

}

Multiple interfaces can be specified as constraints on a single type, as follows: C# class Stack where T : System.IComparable, IEnumerable { } An interface can define more than one type parameter, as follows: C#

interface IDictionary { } The rules of inheritance that apply to classes also apply to interfaces: C# interface IMonth { } interface IJanuary : IMonth { } //No error interface IFebruary : IMonth { } //No error interface IMarch : IMonth { } //No error //interface IApril : IMonth {} //Error Generic interfaces can inherit from non-generic interfaces if the generic interface is contra-variant, which means it only uses its type parameter as a return value. In the .NET Framework class library, IEnumerable<(Of <(T>)>) inherits from IEnumerable because IEnumerable<(Of <(T>)>) only uses T in the return value of GetEnumerator and in the Current property getter. Concrete classes can implement closed constructed interfaces, as follows: C# interface IBaseInterface { } class SampleClass : IBaseInterface<string> { } Generic classes can implement generic interfaces or closed constructed interfaces as long as the class parameter list supplies all arguments required by the interface, as follows: C# interface IBaseInterface1 { } interface IBaseInterface2 { } class SampleClass1 : IBaseInterface1 { } //No error class SampleClass2 : IBaseInterface2 { } //No error The rules that control method overloading are the same for methods within generic classes, generic structs, or generic interfaces Generic Methods A generic method is a method that is declared with type parameters, as follows: C# static void Swap(ref T lhs, ref T rhs) { T temp; temp = lhs; lhs = rhs; rhs = temp; } The following code example shows one way to call the method by using int for the type argument: C# public static void TestSwap() { int a = 1;

int b = 2; Swap(ref a, ref b); System.Console.WriteLine(a + " " + b); } You can also omit the type argument and the compiler will infer it. The following call to Swap is equivalent to the previous call: C# Swap(ref a, ref b); The same rules for type inference apply to static methods and instance methods. The compiler can infer the type parameters based on the method arguments you pass in; it cannot infer the type parameters only from a constraint or return value. Therefore type inference does not work with methods that have no parameters. Type inference occurs at compile time before the compiler tries to resolve overloaded method signatures. The compiler applies type inference logic to all generic methods that share the same name. In the overload resolution step, the compiler includes only those generic methods on which type inference succeeded. Within a generic class, non-generic methods can access the class-level type parameters, as follows: C# class SampleClass { void Swap(ref T lhs, ref T rhs) { } } If you define a generic method that takes the same type parameters as the containing class, the compiler generates warning CS0693 because within the method scope, the argument supplied for the inner T hides the argument supplied for the outer T. If you require the flexibility of calling a generic class method with type arguments other than the ones provided when the class was instantiated, consider providing another identifier for the type parameter of the method, as shown in GenericList2 in the following example. C# class GenericList { // CS0693 void SampleMethod() { } } class GenericList2 { //No warning void SampleMethod() { } } Use constraints to enable more specialized operations on type parameters in methods. This version of Swap, now named SwapIfGreater, can only be used with type arguments that implement IComparable<(Of <(T>)>). C# void SwapIfGreater(ref T lhs, ref T rhs) where T : System.IComparable { T temp; if (lhs.CompareTo(rhs) > 0) { temp = lhs; lhs = rhs;

}

rhs = temp;

} Generic methods can be overloaded on several type parameters. For example, the following methods can all be located in the same class: C# void DoWork() { } void DoWork() { } void DoWork() { } Generics in the .NET Framework Class Library Version 2.0 of the .NET Framework class library provides a new namespace, System.Collections.Generic, which includes several ready-to-use generic collection classes and associated interfaces. Other namespaces, such as System, also provide new generic interfaces such as IComparable<(Of <(T>)>). These classes and interfaces are more efficient and type-safe than the non-generic collection classes provided in earlier releases of the .NET Framework. Before designing and implementing your own custom collection classes, consider whether you can use or derive a class from one of the classes provided in the .NET Framework class library. Generics in the Run Time When a generic type or method is compiled into Microsoft intermediate language (MSIL), it contains metadata that identifies it as having type parameters. How the MSIL for a generic type is used differs based on whether the supplied type parameter is a value type or reference type. When a generic type is first constructed with a value type as a parameter, the runtime creates a specialized generic type with the supplied parameter or parameters substituted in the appropriate locations in the MSIL. Specialized generic types are created one time for each unique value type that is used as a parameter. For example, suppose your program code declared a stack that is constructed of integers: C# Stack stack; At this point, the runtime generates a specialized version of the Stack<(Of <(T>)>) class that has the integer substituted appropriately for its parameter. Now, whenever your program code uses a stack of integers, the runtime reuses the generated specialized Stack<(Of <(T>)>) class. In the following example, two instances of a stack of integers are created, and they share a single instance of the Stack code: C# Stack stackOne = new Stack(); Stack stackTwo = new Stack(); However, suppose that another Stack<(Of <(T>)>) class with a different value type such as a long or a userdefined structure as its parameter is created at another point in your code. As a result, the runtime generates another version of the generic type and substitutes a long in the appropriate locations in MSIL. Conversions are no longer necessary because each specialized generic class natively contains the value type. Generics work somewhat differently for reference types. The first time a generic type is constructed with any reference type, the runtime creates a specialized generic type with object references substituted for the parameters in the MSIL. Then, every time that a constructed type is instantiated with a reference type as its parameter, regardless of what type it is, the runtime reuses the previously created specialized version of the generic type. This is possible because all references are the same size. For example, suppose you had two reference types, a Customer class and an Order class, and also suppose that you created a stack of Customer types:

C# class Customer { } class Order { } C# Stack customers; At this point, the runtime generates a specialized version of the Stack<(Of <(T>)>) class that stores object references that will be filled in later instead of storing data. Suppose the next line of code creates a stack of another reference type, which is named Order: C# Stack orders = new Stack(); Unlike with value types, another specialized version of the Stack<(Of <(T>)>) class is not created for the Order type. Instead, an instance of the specialized version of the Stack<(Of <(T>)>) class is created and the orders variable is set to reference it. Suppose that you then encountered a line of code to create a stack of a Customer type: C# customers = new Stack(); As with the previous use of the Stack<(Of <(T>)>) class created by using the Order type, another instance of the specialized Stack<(Of <(T>)>) class is created. The pointers that are contained therein are set to reference an area of memory the size of a Customer type. Because the number of reference types can vary wildly from program to program, the C# implementation of generics greatly reduces the amount of code by reducing to one the number of specialized classes created by the compiler for generic classes of reference types. Moreover, when a generic C# class is instantiated by using a value type or reference type parameter, reflection can query it at runtime and both its actual type and its type parameter can be ascertained. Generics Sample This sample shows how to create a custom generic list class that has a single type parameter, and how to implement IEnumerable to enable foreach iteration over the contents of the list. The sample also shows how client code creates an instance of the class by specifying a type argument, and how constraints on the type parameter enable additional operations to be performed on the type arguments. For an example of a generic collection class that implements an iterator block, see How to: Create an Iterator Block for a Generic List (C# Programming Guide). To get samples and instructions for installing them Do one or more of the following: On the Help menu, click Samples. The Readme displays information about samples. Visit the Visual Studio 2008 Samples Web site. The most recent versions of samples are available there. Locate samples on the computer on which Visual Studio is installed. By default, samples and a Readme file are installed in drive:\Program Files\Microsoft Visual Studio 9.0\Samples\lcid. For Express editions of Visual Studio, all samples are located online. For more information, see Locating Sample Files. Security Note: This sample code is intended to illustrate a concept, and it shows only the code that is relevant to that concept. It may not meet the security requirements for a specific environment, and it should not be used exactly as shown. We recommend that you add security and error-handling code to make your projects more secure and robust. Microsoft provides this sample code "AS IS" with no warranties.

To build and run the Generics sample within Visual Studio On the Debug menu, click Start Without Debugging. To build and run the Generics sample from a command prompt Type the following at the command prompt: csc generics.cs generics Generic Type Parameters In a generic type or method definition, a type parameters is a placeholder for a specific type that a client specifies when they instantiate a variable of the generic type. A generic class, such as GenericList listed in Introduction to Generics (C# Programming Guide), cannot be used as-is because it is not really a type; it is more like a blueprint for a type. To use GenericList, client code must declare and instantiate a constructed type by specifying a type argument inside the angle brackets. The type argument for this particular class can be any type recognized by the compiler. Any number of constructed type instances can be created, each one using a different type argument, as follows: C# GenericList list1 = new GenericList(); GenericList<ExampleClass> list2 = new GenericList<ExampleClass>(); GenericList<ExampleStruct> list3 = new GenericList<ExampleStruct>(); In each of these instances of GenericList, every occurrence of T in the class will be substituted at run time with the type argument. By means of this substitution, we have created three separate type-safe and efficient objects using a single class definition. For more information on how this substitution is performed by the CLR, see Generics in the Run Time (C# Programming Guide). Type Parameter Naming Guidelines Do name generic type parameters with descriptive names, unless a single letter name is completely self explanatory and a descriptive name would not add value. C# public interface ISessionChannel { /*...*/ } public delegate TOutput Converter<TInput, TOutput>(TInput from); public class List { /*...*/ } Consider using T as the type parameter name for types with one single letter type parameter. C# public int IComparer() { return 0; } public delegate bool Predicate(T item); public struct Nullable where T : struct { /*...*/ } Do prefix descriptive type parameter names with “T”. C# public interface ISessionChannel { TSession Session { get; } } Consider indicating constraints placed on a type parameter in the name of parameter. For example, a parameter constrained to ISession may be called TSession. Introduction to Generics

Generic classes and methods combine reusability, type safety and efficiency in a way that their non-generic counterparts cannot. Generics are most frequently used with collections and the methods that operate on them. Version 2.0 of the .NET Framework class library provides a new namespace, System.Collections.Generic, which contains several new generic-based collection classes. It is recommended that all applications that target the .NET Framework 2.0 and later use the new generic collection classes instead of the older non-generic counterparts such as ArrayList. For more information, see Generics in the .NET Framework Class Library (C# Programming Guide). Of course, you can also create custom generic types and methods to provide your own generalized solutions and design patterns that are type-safe and efficient. The following code example shows a simple generic linked-list class for demonstration purposes. (In most cases, you should use the List<(Of <(T>)>) class provided by the .NET Framework class library instead of creating your own.) The type parameter T is used in several locations where a concrete type would ordinarily be used to indicate the type of the item stored in the list. It is used in the following ways: As the type of a method parameter in the AddHead method. As the return type of the public method GetNext and the Data property in the nested Node class. As the type of the private member data in the nested class. Note that T is available to the nested Node class. When GenericList is instantiated with a concrete type, for example as a GenericList, each occurrence of T will be replaced with int. C# // type parameter T in angle brackets public class GenericList { // The nested class is also generic on T. private class Node { // T used in non-generic constructor. public Node(T t) { next = null; data = t; } private Node next; public Node Next { get { return next; } set { next = value; } } // T as private member data type. private T data; // T as return type of property. public T Data { get { return data; } set { data = value; } } } private Node head;

// constructor public GenericList() { head = null; } // T as method parameter type: public void AddHead(T t) { Node n = new Node(t); n.Next = head; head = n; } public IEnumerator GetEnumerator() { Node current = head; while (current != null) { yield return current.Data; current = current.Next; } }

}

The following code example shows how client code uses the generic GenericList class to create a list of integers. Simply by changing the type argument, the following code could easily be modified to create lists of strings or any other custom type: C# class TestGenericList { static void Main() { // int is the type argument GenericList list = new GenericList(); for (int x = 0; x < 10; x++) { list.AddHead(x); }

}

foreach (int i in list) { System.Console.Write(i + " "); } System.Console.WriteLine("\nDone");

} System.Collections.Generic Namespace The System.Collections.Generic namespace contains interfaces and classes that define generic collections, which allow users to create strongly typed collections that provide better type safety and performance than non-generic strongly typed collections.

Classes Class Comparer<(Of <(T>)>)

Description Provides a base class for implementations of the IComparer<(Of <(T>)>) generic interface. Dictionary<(Of <(TKey, TValue>)>) Represents a collection of keys and values. Dictionary<(Of <(TKey, TValue>)>)..::.KeyCollection Represents the collection of keys in a Dictionary<(Of <(TKey, TValue>)>). This class cannot be inherited. Dictionary<(Of <(TKey, TValue>)>)..::.ValueCollection Represents the collection of values in a Dictionary<(Of <(TKey, TValue>)>). This class cannot be inherited. EqualityComparer<(Of <(T>)>) Provides a base class for implementations of the IEqualityComparer<(Of <(T>)>) generic interface. HashSet<(Of <(T>)>) Represents a set of values. KeyedByTypeCollection<(Of <(TItem>)>) Provides a collection whose items are types that serve as keys. KeyNotFoundException The exception that is thrown when the key specified for accessing an element in a collection does not match any key in the collection. LinkedList<(Of <(T>)>) Represents a doubly linked list. LinkedListNode<(Of <(T>)>) Represents a node in a LinkedList<(Of <(T>)>). This class cannot be inherited. List<(Of <(T>)>) Represents a strongly typed list of objects that can be accessed by index. Provides methods to search, sort, and manipulate lists. Queue<(Of <(T>)>) Represents a first-in, first-out collection of objects. SortedDictionary<(Of <(TKey, TValue>)>) Represents a collection of key/value pairs that are sorted on the key. SortedDictionary<(Of <(TKey, TValue>)>)..::.KeyCollection Represents the collection of keys in a SortedDictionary<(Of <(TKey, TValue>)>). This class cannot be inherited. SortedDictionary<(Of <(TKey, TValue>)>)..::.ValueCollection Represents the collection of values in a SortedDictionary<(Of <(TKey, TValue>)>). This class cannot be inherited SortedList<(Of <(TKey, TValue>)>) Represents a collection of key/value pairs that are sorted by key based on the associated IComparer<(Of <(T>)>) implementation. Stack<(Of <(T>)>) Represents a variable size last-in-first-out (LIFO) collection of instances of the same arbitrary type. SynchronizedCollection<(Of <(T>)>) Provides a thread-safe collection that contains objects of a type specified by the generic parameter as elements. SynchronizedKeyedCollection<(Of <(K, T>)>) Provides a thread-safe collection that contains objects of a type specified by a generic parameter and that are grouped by keys. SynchronizedReadOnlyCollection<(Of <(T>)>) Provides a thread-safe, read-only collection that contains objects of a type specified by the generic parameter as elements. Structures Structure Dictionary<(Of <(TKey, TValue>)>)..::.Enumerator

Description Enumerates the elements of a Dictionary<(Of <(TKey, TValue>)>).

Dictionary<(Of <(TKey, TValue>)>)..::.KeyCollection..::.Enumerator Enumerates the elements of a Dictionary<(Of <(TKey, TValue>)>)..::.KeyCollection. Dictionary<(Of <(TKey, TValue>)>)..::.ValueCollection..::.Enumerator Enumerates the elements of a Dictionary<(Of <(TKey, TValue>)>)..::.ValueCollection. HashSet<(Of <(T>)>)..::.Enumerator Enumerates the elements of a HashSet<(Of <(T>)>) object. KeyValuePair<(Of <(TKey, TValue>)>) Defines a key/value pair that can be set or retrieved. LinkedList<(Of <(T>)>)..::.Enumerator Enumerates the elements of a LinkedList<(Of <(T>)>). List<(Of <(T>)>)..::.Enumerator Enumerates the elements of a List<(Of <(T>)>). Queue<(Of <(T>)>)..::.Enumerator Enumerates the elements of a Queue<(Of <(T>)>). SortedDictionary<(Of <(TKey, TValue>)>)..::.Enumerator Enumerates the elements of a SortedDictionary<(Of <(TKey, TValue>)>). SortedDictionary<(Of <(TKey, TValue>)>)..::.KeyCollection..::.Enumerator Enumerates the elements of a SortedDictionary<(Of <(TKey, TValue>)>)..::.KeyCollection. SortedDictionary<(Of <(TKey, TValue>)>)..::.ValueCollection..::.Enumerator Enumerates the elements of a SortedDictionary<(Of <(TKey, TValue>)>)..::.ValueCollection. Stack<(Of <(T>)>)..::.Enumerator Enumerates the elements of a Stack<(Of <(T>)>). Interfaces Interface Description ICollection<(Of <(T>)>) Defines methods to manipulate generic collections. IComparer<(Of <(T>)>) Defines a method that a type implements to compare two objects. IDictionary<(Of <(TKey, TValue>)>) Represents a generic collection of key/value pairs. IEnumerable<(Of <(T>)>) Exposes the enumerator, which supports a simple iteration over a collection of a specified type. IEnumerator<(Of <(T>)>) Supports a simple iteration over a generic collection. IEqualityComparer<(Of <(T>)>) Defines methods to support the comparison of objects for equality. IList<(Of <(T>)>) Represents a collection of objects that can be individually accessed by index. Hashtable class What is the Hashtable? The Hashtable class represents a collection of key/value pairs that are organized based on the hash code of the key. Each element is a key/value pair stored in a DictionaryEntry object. A key cannot be a null reference , but a value can be. Things To Keep In Mind When Creating The Hashtable The objects used as keys by a Hashtable are required to override the Object.GetHashCode method (or the IHashCodeProvider interface) and the Object.Equals method (or the IComparer interface). The implementation of both methods and interfaces must handle case sensitivity the same way; otherwise, the Hashtable might behave incorrectly. For example, when creating a Hashtable, you must use the CaseInsensitiveHashCodeProvider class (or any case-insensitive IHashCodeProvider implementation) with the CaseInsensitiveComparer class (or any case-insensitive IComparer implementation). Furthermore, these methods must produce the same results when called with the same parameters while the key exists in the Hashtable. An alternative is to use a Hashtable constructor with an IEqualityComparer parameter. If key equality were simply reference equality, the inherited implementation of Object.GetHashCode and Object.Equals would suffice. Key objects must be immutable as long as they are used as keys in the Hashtable.

How The Hashtable Works When an element is added to the Hashtable, the element is placed into a bucket based on the hash code of the key. Subsequent lookups of the key use the hash code of the key to search in only one particular bucket, thus substantially reducing the number of key comparisons required to find an element. The load factor of a Hashtable determines the maximum ratio of elements to buckets. Smaller load factors cause faster average lookup times at the cost of increased memory consumption. The default load factor of 1.0 generally provides the best balance between speed and size. A different load factor can also be specified when the Hashtable is created. As elements are added to a Hashtable, the actual load factor of the Hashtable increases. When the actual load factor reaches the specified load factor, the number of buckets in the Hashtable is automatically increased to the smallest prime number that is larger than twice the current number of Hashtable buckets. Each key object in the Hashtable must provide its own hash function, which can be accessed by calling GetHash. However, any object implementing IHashCodeProvider can be passed to a Hashtable constructor, and that hash function is used for all objects in the table. The capacity of a Hashtable is the number of elements the Hashtable can hold. As elements are added to a Hashtable, the capacity is automatically increased as required through reallocation. The foreach statement of the C# language requires the type of each element in the collection. Since each element of the Hashtable is a key/value pair, the element type is not the type of the key or the type of the value. Instead, the element type is DictionaryEntry. The foreach statement is a wrapper around the enumerator, which only allows reading from, not writing to, the collection. Because serializing and deserializing an enumerator for a Hashtable can cause the elements to become reordered, it is not possible to continue enumeration without calling the Reset method. Because keys can be inherited and their behavior changed, their absolute uniqueness cannot be guaranteed by comparisons using the Equals method. Code Examples Adding Elements To The Table // Add some elements to the hash table. There are no duplicate keys, but some of the values are duplicates. exampleTable.Add( "txt", "notepad.exe" ); exampleTable.Add( "bmp", "paint.exe" ); exampleTable.Add( "dib", "paint.exe" ); exampleTable.Add( "rtf", "wordpad.exe" ); Using The Default Item Property To Change Its Corresponding Key // The default Item property can be used to change the value associated with a key. exampleTable[ "rtf" ] = "winword.exe"; // If a key does not exist, setting the default Item property // for that key adds a new key/value pair. exampleTable[ "doc" ] = "winword.exe"; //ContainsKey can be used to test keys before inserting them. if( !exampleTable.ContainsKey( "ht" ) ) { exampleTable.Add( "ht", "hypertrm.exe" ); } Using The Remove Method To Delete A Value Or Key From The Table // Use the Remove method to remove a key/value pair. exampleTable.Remove( "doc" ); Hashtable Class Represents a collection of key/value pairs that are organized based on the hash code of the key. Namespace: System.Collections Assembly: mscorlib (in mscorlib.dll)

Syntax Visual Basic (Declaration) <SerializableAttribute> _ _ Public Class Hashtable _ Implements IDictionary, ICollection, IEnumerable, ISerializable, _ IDeserializationCallback, ICloneable Visual Basic (Usage) Dim instance As Hashtable C# [SerializableAttribute] [ComVisibleAttribute(true)] public class Hashtable : IDictionary, ICollection, IEnumerable, ISerializable, IDeserializationCallback, ICloneable Remarks Each element is a key/value pair stored in a DictionaryEntry object. A key cannot be nullNothingnullptra null reference (Nothing in Visual Basic), but a value can be. The objects used as keys by a Hashtable are required to override the Object..::.GetHashCode method (or the IHashCodeProvider interface) and the Object..::.Equals method (or the IComparer interface). The implementation of both methods and interfaces must handle case sensitivity the same way; otherwise, the Hashtable might behave incorrectly. For example, when creating a Hashtable, you must use the CaseInsensitiveHashCodeProvider class (or any case-insensitive IHashCodeProvider implementation) with the CaseInsensitiveComparer class (or any case-insensitive IComparer implementation). Furthermore, these methods must produce the same results when called with the same parameters while the key exists in the Hashtable. An alternative is to use a Hashtable constructor with an IEqualityComparer parameter. If key equality were simply reference equality, the inherited implementation of Object..::.GetHashCode and Object..::.Equals would suffice. Key objects must be immutable as long as they are used as keys in the Hashtable. When an element is added to the Hashtable, the element is placed into a bucket based on the hash code of the key. Subsequent lookups of the key use the hash code of the key to search in only one particular bucket, thus substantially reducing the number of key comparisons required to find an element. The load factor of a Hashtable determines the maximum ratio of elements to buckets. Smaller load factors cause faster average lookup times at the cost of increased memory consumption. The default load factor of 1.0 generally provides the best balance between speed and size. A different load factor can also be specified when the Hashtable is created. As elements are added to a Hashtable, the actual load factor of the Hashtable increases. When the actual load factor reaches the specified load factor, the number of buckets in the Hashtable is automatically increased to the smallest prime number that is larger than twice the current number of Hashtable buckets. Each key object in the Hashtable must provide its own hash function, which can be accessed by calling GetHash. However, any object implementing IHashCodeProvider can be passed to a Hashtable constructor, and that hash function is used for all objects in the table. The capacity of a Hashtable is the number of elements the Hashtable can hold. As elements are added to a Hashtable, the capacity is automatically increased as required through reallocation. vb#c#

The foreach statement of the C# language (for each in Visual Basic) requires the type of each element in the collection. Since each element of the Hashtable is a key/value pair, the element type is not the type of the key or the type of the value. Instead, the element type is DictionaryEntry. For example: C# foreach (DictionaryEntry de in myHashtable) {...} Visual Basic Copy Code For Each de as DictionaryEntry In myHashtable ... Next de vb#c# The foreach statement is a wrapper around the enumerator, which only allows reading from, not writing to, the collection. Because serializing and deserializing an enumerator for a Hashtable can cause the elements to become reordered, it is not possible to continue enumeration without calling the Reset method. Note: Because keys can be inherited and their behavior changed, their absolute uniqueness cannot be guaranteed by comparisons using the Equals method. Examples The following example shows how to create, initialize and perform various functions to a Hashtable and how to print out its keys and values. Visual Basic Copy Code Imports System Imports System.Collections Module Example Sub Main() ' Create a new hash table. ' Dim openWith As New Hashtable() ' Add some elements to the hash table. There are no ' duplicate keys, but some of the values are duplicates. openWith.Add("txt", "notepad.exe") openWith.Add("bmp", "paint.exe") openWith.Add("dib", "paint.exe") openWith.Add("rtf", "wordpad.exe") ' The Add method throws an exception if the new key is ' already in the hash table. Try openWith.Add("txt", "winword.exe") Catch Console.WriteLine("An element with Key = ""txt"" already exists.") End Try ' The Item property is the default property, so you ' can omit its name when accessing elements. Console.WriteLine("For key = ""rtf"", value = {0}.", _ openWith("rtf"))

' The default Item property can be used to change the value ' associated with a key. openWith("rtf") = "winword.exe" Console.WriteLine("For key = ""rtf"", value = {0}.", _ openWith("rtf")) ' If a key does not exist, setting the default Item property ' for that key adds a new key/value pair. openWith("doc") = "winword.exe" ' ContainsKey can be used to test keys before inserting ' them. If Not openWith.ContainsKey("ht") Then openWith.Add("ht", "hypertrm.exe") Console.WriteLine("Value added for key = ""ht"": {0}", _ openWith("ht")) End If ' When you use foreach to enumerate hash table elements, ' the elements are retrieved as KeyValuePair objects. Console.WriteLine() For Each de As DictionaryEntry In openWith Console.WriteLine("Key = {0}, Value = {1}", _ de.Key, de.Value) Next de ' To get the values alone, use the Values property. Dim valueColl As ICollection = openWith.Values ' The elements of the ValueCollection are strongly typed ' with the type that was specified for hash table values. Console.WriteLine() For Each s As String In valueColl Console.WriteLine("Value = {0}", s) Next s ' To get the keys alone, use the Keys property. Dim keyColl As ICollection = openWith.Keys ' The elements of the KeyCollection are strongly typed ' with the type that was specified for hash table keys. Console.WriteLine() For Each s As String In keyColl Console.WriteLine("Key = {0}", s) Next s ' Use the Remove method to remove a key/value pair. Console.WriteLine(vbLf + "Remove(""doc"")") openWith.Remove("doc") If Not openWith.ContainsKey("doc") Then Console.WriteLine("Key ""doc"" is not found.") End If End Sub End Module

' This code example produces the following output: ' 'An element with Key = "txt" already exists. 'For key = "rtf", value = wordpad.exe. 'For key = "rtf", value = winword.exe. 'Value added for key = "ht": hypertrm.exe ' 'Key = dib, Value = paint.exe 'Key = txt, Value = notepad.exe 'Key = ht, Value = hypertrm.exe 'Key = bmp, Value = paint.exe 'Key = rtf, Value = winword.exe 'Key = doc, Value = winword.exe ' 'Value = paint.exe 'Value = notepad.exe 'Value = hypertrm.exe 'Value = paint.exe 'Value = winword.exe 'Value = winword.exe ' 'Key = dib 'Key = txt 'Key = ht 'Key = bmp 'Key = rtf 'Key = doc ' 'Remove("doc") 'Key "doc" is not found. C# using System; using System.Collections; class Example { public static void Main() { // Create a new hash table. // Hashtable openWith = new Hashtable(); // Add some elements to the hash table. There are no // duplicate keys, but some of the values are duplicates. openWith.Add("txt", "notepad.exe"); openWith.Add("bmp", "paint.exe"); openWith.Add("dib", "paint.exe"); openWith.Add("rtf", "wordpad.exe"); // The Add method throws an exception if the new key is // already in the hash table. try { openWith.Add("txt", "winword.exe"); }

catch { Console.WriteLine("An element with Key = \"txt\" already exists."); } // The Item property is the default property, so you // can omit its name when accessing elements. Console.WriteLine("For key = \"rtf\", value = {0}.", openWith["rtf"]); // The default Item property can be used to change the value // associated with a key. openWith["rtf"] = "winword.exe"; Console.WriteLine("For key = \"rtf\", value = {0}.", openWith["rtf"]); // If a key does not exist, setting the default Item property // for that key adds a new key/value pair. openWith["doc"] = "winword.exe"; // ContainsKey can be used to test keys before inserting // them. if (!openWith.ContainsKey("ht")) { openWith.Add("ht", "hypertrm.exe"); Console.WriteLine("Value added for key = \"ht\": {0}", openWith["ht"]); } // When you use foreach to enumerate hash table elements, // the elements are retrieved as KeyValuePair objects. Console.WriteLine(); foreach( DictionaryEntry de in openWith ) { Console.WriteLine("Key = {0}, Value = {1}", de.Key, de.Value); } // To get the values alone, use the Values property. ICollection valueColl = openWith.Values; // The elements of the ValueCollection are strongly typed // with the type that was specified for hash table values. Console.WriteLine(); foreach( string s in valueColl ) { Console.WriteLine("Value = {0}", s); } // To get the keys alone, use the Keys property. ICollection keyColl = openWith.Keys; // The elements of the KeyCollection are strongly typed // with the type that was specified for hash table keys. Console.WriteLine(); foreach( string s in keyColl ) { Console.WriteLine("Key = {0}", s); } // Use the Remove method to remove a key/value pair.

Console.WriteLine("\nRemove(\"doc\")"); openWith.Remove("doc"); if (!openWith.ContainsKey("doc")) { Console.WriteLine("Key \"doc\" is not found."); }

} }

/* This code example produces the following output: An element with Key = "txt" already exists. For key = "rtf", value = wordpad.exe. For key = "rtf", value = winword.exe. Value added for key = "ht": hypertrm.exe Key Key Key Key Key Key

= = = = = =

dib, Value = paint.exe txt, Value = notepad.exe ht, Value = hypertrm.exe bmp, Value = paint.exe rtf, Value = winword.exe doc, Value = winword.exe

Value Value Value Value Value Value

= = = = = =

Key Key Key Key Key Key

dib txt ht bmp rtf doc

= = = = = =

paint.exe notepad.exe hypertrm.exe paint.exe winword.exe winword.exe

Remove("doc") Key "doc" is not found. */ Inheritance Hierarchy System..::.Object System.Collections..::.Hashtable System.Configuration..::.SettingsAttributeDictionary System.Configuration..::.SettingsContext System.Data..::.PropertyCollection System.Printing.IndexedProperties..::.PrintPropertyDictionary Thread Safety Hashtable is thread safe for use by multiple reader threads and a single writing thread. It is thread safe for multi-thread use when only one of the threads perform write (update) operations, which allows for lock-free reads provided that the writers are serialized to the Hashtable. To support multiple writers all operations on the Hashtable must be done through the wrapper returned by the Synchronized method, provided that there are no threads reading the Hashtable object.

Enumerating through a collection is intrinsically not a thread safe procedure. Even when a collection is synchronized, other threads can still modify the collection, which causes the enumerator to throw an exception. To guarantee thread safety during enumeration, you can either lock the collection during the entire enumeration or catch the exceptions resulting from changes made by other threads. ICloneable The System.ICloneable interface defines a method of cloning—copying—to create a new instance of a class with the identical value as an existing instance. There are two ways to clone an instance: Shallow copy - may be linked to data shared by both the original and the copy Deep copy - contains the complete encapsulated data of the original object A shallow copy is by far the easiest way to clone your class. This can be achieved with the MemberwiseClone method inherited by all classes from Object. However, you may find that this is not exactly what you want. Syntax Declaration syntax [ComVisibleAttribute(true)] public interface ICloneable[edit]Method syntax The Clone method creates a new object—a copy of the current instance. Object Clone ()Returns a new object that is a copy of the current instance. Example scenario To illustrate the differences between deep and shallow copies, the following scenario has been created. In addition to a string variable, a Job class contains a reference to a Duties class. Job class class Job { string m_JobName; Duties m_Duties; public Job(string jobName) { m_JobName = jobName; } public string getJobName() { return m_JobName; } public void setDuties(string DutyA, string DutyB) { m_Duties = new Duties(DutyA, DutyB); } public Duties getDuties() { return m_Duties; } }Duties class class Duties { string m_DutyA;

string m_DutyB; public Duties(string dutyA, string dutyB) { m_DutyA = dutyA; m_DutyB = dutyB; } public string getDutyA() { return m_DutyA; } public string getDutyB() { return m_DutyB; } }Person class class Person : ICloneable { string m_Name; int m_Age; Job m_CurrentJob; public Person(string name, int age) { m_Name = name; m_Age = age; } public void getJob(Job jobName) { m_CurrentJob = jobName; } public Job getCurrentJob() { return m_CurrentJob; } public override string ToString() { return this.m_Name; } public object Clone() { return this.MemberwiseClone(); // call clone method } }ICloneableExample class class ICloneableExample { static void Main() { Job swimPool = new Job(" Swimming Pool Attendant "); swimPool.setDuties("rescue swimmers in difficulty ", "water quality control ");

Person nicola = new Person("Nicola", 23); nicola.getJob(swimPool); Person nicolaClone = (Person)nicola.Clone();

// clone

Console.WriteLine("(Nicola)"); printInfo(nicola); Console.WriteLine("(NicolaClone)"); printInfo(nicolaClone); Console.WriteLine("\r\n *NicolaClones' Job Duties change* \r\n"); nicolaClone.getCurrentJob().setDuties("Clean Pool", "Welcome Customers");

}

Console.WriteLine("(Nicola)"); printInfo(nicola); Console.WriteLine("(NicolaClone)"); printInfo(nicolaClone);

static void printInfo(Person person) { Console.WriteLine("Name: {0}", person); Console.WriteLine(" Job: {0}", person.getCurrentJob().getJobName()); Console.WriteLine(" Duty A: {0}", person.getCurrentJob().getDuties().getDutyA()); Console.WriteLine(" Duty B: {0}", person.getCurrentJob().getDuties().getDutyB()); } }MemberwiseClone The Person.Clone method simply calls the Object.MemberwiseClone method to make a shallow copy of the instance. ICloneableExample (program output) (Nicola) Name: Nicola Job: Swimming Pool Attendant Duty A: rescue swimmers in difficulty Duty B: water quality control (NicolaClone) Name: Nicola Job: Swimming Pool Attendant Duty A: rescue swimmers in difficulty Duty B: water quality control *NicolaClones' Job Duties change* (Nicola) Name: Nicola Job: Swimming Pool Attendant Duty A: Clean Pool Duty B: Welcome Customers (NicolaClone) Name: Nicola Job: Swimming Pool Attendant

Duty A: Clean Pool Duty B: Welcome Customers Notice that the duties of both the original and the clone have changed. Shallow copy example What has been created above is called a shallow copy. Meaning, only the top level class is actually copied to the heap. If that top level class contains any references to instances, only the references will be copied. So, original and clone are exactly the same object, hence why changing duties for one copy changes both copies. To demonstrate this further, a shallow change can be done—for example: changing the person’s name. Person Class - Additional method public void changeName(string name) { m_Name = name; }Updated Main method static void Main() { Job swimPool = new Job(" Swimming Pool Attendant "); swimPool.setDuties("rescue swimmers in difficulty ", "water quality control "); Person nicola = new Person("Nicola", 23); nicola.getJob(swimPool); Person nicolaClone = (Person)nicola.Clone(); Console.WriteLine("(Nicola)"); printInfo(nicola); Console.WriteLine("(NicolaClone)"); printInfo(nicolaClone); Console.WriteLine("\r\n *NicolaClone changes name* \r\n"); nicolaClone.changeName("Becky");

}

Console.WriteLine("(Nicola)"); printInfo(nicola); Console.WriteLine("(NicolaClone)"); printInfo(nicolaClone);

ICloneableExample (program output) (Nicola) Name: Nicola Job: Swimming Pool Attendant Duty A: rescue swimmers in difficulty Duty B: water quality control (NicolaClone) Name: Nicola Job: Swimming Pool Attendant Duty A: rescue swimmers in difficulty Duty B: water quality control *NicolaClone changes name*

(Nicola) Name: Nicola Job: Swimming Pool Attendant Duty A: rescue swimmers in difficulty Duty B: water quality control (NicolaClone) Name: Becky Job: Swimming Pool Attendant Duty A: rescue swimmers in difficulty Duty B: water quality control Notice how the name has changed. Although a string is a reference type it has been copied due to it being a system type. [edit]Deep copy example In a Deep copy, the clone method requires additional code to create new instances of any classes referenced by the original. This example uses the first version of Main. Updated Clone method public object Clone() { Person Copy = new Person(this.m_Name, this.m_Age); Job CopyJob = new Job(this.m_CurrentJob.getJobName()); CopyJob.setDuties (this.m_CurrentJob.getDuties().getDutyA(), this.m_CurrentJob.getDuties().getDutyB()); Copy.getJob(CopyJob); return Copy; } ICloneableExample (program output) (Nicola) Name: Nicola Job: Swimming Pool Attendant Duty A: rescue swimmers in difficulty Duty B: water quality control (NicolaClone) Name: Nicola Job: Swimming Pool Attendant Duty A: rescue swimmers in difficulty Duty B: water quality control *NicolaClones' Job Duties change* (Nicola) Name: Nicola Job: Swimming Pool Attendant Duty A: rescue swimmers in difficulty Duty B: water quality control (NicolaClone) Name: Nicola Job: Swimming Pool Attendant Duty A: Clean Pool Duty B: Welcome Customers

Design to be cloned In the previous example, all cloning was done by just one class, the Person class. This means that the Person class must understand how to clone not only itself, but also a Job and the Jobs' Duties. Although this does mean that all cloning is done in one place it does not support the 'OO' principal of encapsulation. That is to say that if a class could be used in a different project then it should be able to work without the user class understanding the inner workings. To support this each class can have its own Clone method. The following shows how a class can be designed or changed to allow the use of class cloning which in turn promotes encapsulation. Clone-unfriendly example class Job : ICloneable { string m_JobName; Duties m_Duties; public Job(string jobName) { m_JobName = jobName; } public string getJobName() { return m_JobName; } /********************************************************* * This should be phased out ASAP! * * If Duties change this will have to be changed * * This goes against encapsulation rules where public * * methods should always remain the same. * *********************************************************/ public void setDuties(string DutyA, string DutyB) { m_Duties = new Duties(DutyA, DutyB); } public Duties getDuties() { return m_Duties; } public object Clone() { Job copy = new Job(this.m_JobName); /***************************************************************** * The Job class must understand how to set duties. * * If Duties change then the Job class will also have to change! * *****************************************************************/ copy.setDuties(this.m_Duties.getDutyA(),this.m_Duties.getDutyB()); return copy; } }

Clone-friendly example class Job : ICloneable { string m_JobName; Duties m_Duties; public Job(string jobName) { m_JobName = jobName; } public string getJobName() { return m_JobName; } /********************************************************* * Overload the method, this allows the existing * * method to remain for older code which uses it. * * * * This design works even if the Duties class is changed! * *********************************************************/ public void setDuties(Duties duties) { m_Duties = duties; } public Duties getDuties() { return m_Duties; } public object Clone() { Job copy = new Job(this.m_JobName); /****************************************************** * Duties knows more about itself than any other class * * So let it clone itself! * ******************************************************/ copy.setDuties((Duties) this.m_Duties.Clone()); return copy; } } The final main classes The clone friendly classes follow: class Person : ICloneable { string m_Name; int m_Age; Job m_CurrentJob; public Person(string name, int age)

{ }

m_Name = name; m_Age = age;

public void getJob(Job jobName) { m_CurrentJob = jobName; } public Job getCurrentJob() { return m_CurrentJob; } public void changeName(string name) { m_Name = name; } public override string ToString() { return this.m_Name; } #region ICloneable Members public object Clone() { Person Copy = new Person(this.m_Name, this.m_Age); Copy.getJob((Job) this.getCurrentJob().Clone()); return Copy; } #endregion }class Job : ICloneable { string m_JobName; Duties m_Duties; public Job(string jobName) { m_JobName = jobName; } public string getJobName() { return m_JobName; } public void setDuties(Duties duties) { m_Duties = duties; } public Duties getDuties() {

}

return m_Duties;

#region ICloneable Members public object Clone() { Job copy = new Job(this.m_JobName); copy.setDuties((Duties) this.m_Duties.Clone()); }

return copy;

#endregion }class Duties: ICloneable { string m_DutyA; string m_DutyB; public Duties(string dutyA, string dutyB) { m_DutyA = dutyA; m_DutyB = dutyB; } public string getDutyA() { return m_DutyA; } public string getDutyB() { return m_DutyB; } #region ICloneable Members public object Clone() { Duties copy = new Duties(this.m_DutyA, this.m_DutyB); return copy; } #endregion } Example Note that only a slight change had to be made in the way that duties are set due to phasing out the cloneunfriendly method. static void Main() { Job swimPool = new Job(" Swimming Pool Attendant "); swimPool.setDuties ( new Duties("rescue swimmers in difficulty ", "water quality control "));

Person nicola = new Person("Nicola", 23); nicola.getJob(swimPool); Person nicolaClone = (Person)nicola.Clone(); Console.WriteLine("(Nicola)"); printInfo(nicola); Console.WriteLine("(NicolaClone)"); printInfo(nicolaClone); Console.WriteLine("\r\n *NicolaClones' Job Duties change* \r\n"); nicolaClone.getCurrentJob().setDuties ( new Duties("Clean Pool", "Welcome Customers")); Console.WriteLine("(Nicola)"); printInfo(nicola); Console.WriteLine("(NicolaClone)"); printInfo(nicolaClone); } static void printInfo(Person person) { Console.WriteLine("Name: {0}", person); Console.WriteLine(" Job: {0}", person.getCurrentJob().getJobName()); Console.WriteLine(" Duty A: {0}", person.getCurrentJob().getDuties().getDutyA()); Console.WriteLine(" Duty B: {0}", person.getCurrentJob().getDuties().getDutyB()); } ICloneable Interface Supports cloning, which creates a new instance of a class with the same value as an existing instance. Namespace: System Assembly: mscorlib (in mscorlib.dll) Syntax Visual Basic (Declaration) _ Public Interface ICloneable Visual Basic (Usage) Dim instance As ICloneable C# [ComVisibleAttribute(true)] public interface ICloneable Remarks The ICloneable interface contains one member, Clone, which is intended to support cloning beyond that supplied by MemberwiseClone. Object..::.MemberwiseClone Method Creates a shallow copy of the current Object. Namespace: System Assembly: mscorlib (in mscorlib.dll) Syntax Visual Basic (Declaration)

Protected Function MemberwiseClone As Object Visual Basic (Usage) Dim returnValue As Object returnValue = Me.MemberwiseClone() C# protected Object MemberwiseClone() Return Value Type: System..::.Object A shallow copy of the current Object. Remarks The MemberwiseClone method creates a shallow copy by creating a new object, and then copying the nonstatic fields of the current object to the new object. If a field is a value type, a bit-by-bit copy of the field is performed. If a field is a reference type, the reference is copied but the referred object is not; therefore, the original object and its clone refer to the same object. For example, consider an object called X that references objects A and B. Object B, in turn, references object C. A shallow copy of X creates new object X2 that also references objects A and B. In contrast, a deep copy of X creates a new object X2 that references the new objects A2 and B2, which are copies of A and B. B2, in turn, references the new object C2, which is a copy C. Use a class that implements the ICloneable interface to perform a deep or shallow copy of an object. Examples The following code example shows how to copy an instance of a class using MemberwiseClone. Visual Basic Imports System Class MyBaseClass Public Shared CompanyName As String = "My Company" Public age As Integer Public name As String End Class 'MyBaseClass Class MyDerivedClass Inherits MyBaseClass Shared Sub Main() ' Creates an instance of MyDerivedClass and assign values to its fields. Dim m1 As New MyDerivedClass() m1.age = 42 m1.name = "Sam" ' Performs a shallow copy of m1 and assign it to m2. Dim m2 As MyDerivedClass = CType(m1.MemberwiseClone(), MyDerivedClass) End Sub 'Main End Class 'MyDerivedClass C# using System; class MyBaseClass {

}

public static string CompanyName = "My Company"; public int age; public string name;

class MyDerivedClass: MyBaseClass { static void Main() { // Creates an instance of MyDerivedClass and assign values to its fields. MyDerivedClass m1 = new MyDerivedClass(); m1.age = 42; m1.name = "Sam";

}

// Performs a shallow copy of m1 and assign it to m2. MyDerivedClass m2 = (MyDerivedClass) m1.MemberwiseClone(); }

IComparable The System.IComparable interface defines a generalized comparison method to be implemented by a value type or class. It is used to create a type-specific method for comparing and ordering instances. Generic version (preferred) Syntax Declaration syntax public interface IComparableThe IComparable interface defines the CompareTo method: Method syntax int CompareTo (T comparee)where comparee is an object to be compared with this object. Return value Meaning Less than zero (< 0) Comparer < Comparee Zero (0) Comparer = Comparee Greater than zero (> 0) Comparer > Comparee Usage Simple equality (==) example class Vector { private double m_X, double m_Y, double m_Z; public Vector(double x, double y, double z) { m_X = x; m_Y = y; m_Z = z; } public double getX() { return m_X; } public double getY() { return m_Y; } public double getZ() { return m_Z; } }Vector myVA = new Vector(1.5, 1.5, 1.5); Vector myVB = new Vector(1.5, 1.5, 1.5);

if (myVA == myVB) { Console.WriteLine("myVA = myVB"); } else { Console.WriteLine("myVA != myVB"); }Output: myVA != myVBThe reason for this result is that the == compares the value stored in the variables myVA and myVB. Because these represent instances of classes, they are reference types; so, the values are memory addresses where the actual objects are stored on the heap. Therefore, they can never be identical unless they actually point to the same object as follows: Vector myVA = new Vector(1.5, 1.5, 1.5); Vector myVB = myVA; if (myVA == myVB) { Console.WriteLine("myVA = myVB"); } else { Console.WriteLine("myVA != myVB"); }Output: myVA = myVB[edit]CompareTo() When implementing IComparable you a must create a CompareTo(Comparee) method which returns an int indicating three main states: Return value Meaning Less than zero (< 0) Comparer < Comparee Zero (0) Comparer = Comparee Greater than zero (> 0) Comparer > Comparee This means you must give some thought to what you actually want to compare of the class. With the Vector class the most likely attribute to compare is the magnitude. With this in mind the Vector class now becomes: class Vector : IComparable { private double m_Xm double m_Y, double m_Z; public Vector(double x, double y, double z) { m_X = x; m_Y = y; m_Z = z; } public double getX() { return m_X; } public double getY() { return m_Y; } public double getZ() { return m_Z; } #region IComparable Members

public int CompareTo(Vector other) { Double magnitudeThis = 0; Double magnitudeThat = 0; int returnValue = 0; magnitudeThis += Math.Pow(m_X, 2); magnitudeThis += Math.Pow(m_Y, 2); magnitudeThis += Math.Pow(m_Z, 2); magnitudeThat += Math.Pow(other.getX(), 2); magnitudeThat += Math.Pow(other.getY(), 2); magnitudeThat += Math.Pow(other.getZ(), 2); magnitudeThis = Math.Sqrt(magnitudeThis); magnitudeThat = Math.Sqrt(magnitudeThat); //In practice catch the exception! returnValue = Convert.ToInt32((magnitudeThis - magnitudeThat)); }

return returnValue;

#endregion }Vector myVA = new Vector(1.5, 1.5, 1.5); Vector myVB = new Vector(1.5, 1.5, 1.5); if (myVA.CompareTo(myVB) == 0) { Console.WriteLine("myVA = myVB"); } else { Console.WriteLine("myVA != myVB"); }Output: myVA = myVB[edit]Non-generic version (backward compatible) [edit]Syntax [edit]Declaration syntax [ComVisibleAttribute(true)] public interface IComparable[edit]Method syntax The IComparable interface defines the CompareTo method: int CompareTo (Object comparee)where comparee is an object to be compared with this object. Non-Generic type checking If you do not use the generic IComparable, then you must type check the comparee object and either cast it within the CompareTo method or throw an exception if it is not comparable. This means that possible errors will now only be caught at runtime instead of compile time. Note: The example now has extra code as it has to check for this exception and, also, have to cast the object each time. class Vector : IComparable { private double m_X, double m_Y, double m_Z; public Vector(double x, double y, double z) {

}

m_X = x; m_Y = y; m_Z = z;

public double getX() { return m_X; } public double getY() { return m_Y; } public double getZ() { return m_Z; } #region IComparable Members public int CompareTo(object obj) { if (obj is Vector) { Vector that = (Vector) obj; Double magnitudeThis = 0; Double magnitudeThat = 0; int returnValue = 0; magnitudeThis += Math.Pow(m_X, 2); magnitudeThis += Math.Pow(m_Y, 2); magnitudeThis += Math.Pow(m_Z, 2); magnitudeThat += Math.Pow(that.getX(), 2); magnitudeThat += Math.Pow(that.getY(), 2); magnitudeThat += Math.Pow(that.getZ(), 2); magnitudeThis = Math.Sqrt(magnitudeThis); magnitudeThat = Math.Sqrt(magnitudeThat); //In practice catch the exception! returnValue = Convert.ToInt32((magnitudeThis - magnitudeThat)); return returnValue; }

}

throw new ArgumentException("Object cannot be compared"); } #endregion

IComparable Interface Defines a generalized type-specific comparison method that a value type or class implements to order or sort its instances. Namespace: System Assembly: mscorlib (in mscorlib.dll) Syntax Visual Basic (Declaration) _ Public Interface IComparable Visual Basic (Usage)

Dim instance As IComparable C# [ComVisibleAttribute(true)] public interface IComparable Remarks This interface is implemented by types whose values can be ordered or sorted. It requires that implementing types define a single method, CompareTo, that indicates whether the position of the current instance in the sort order is before, after, or the same as a second object of the same type. The instance's IComparable implementation is called automatically by methods such as Array..::.Sort and ArrayList..::.Sort. All numeric types (such as Int32 and Double) implement IComparable, as do String, Char, and DateTime. Custom types should also provide their own implementation of IComparable to enable object instances to be ordered or sorted. Examples The following code sample illustrates the implementation of IComparable and the requisite CompareTo method. Visual Basic Imports System.Collections Public Class Temperature Implements IComparable ' The temperature value Protected temperatureF As Double Public Overloads Function CompareTo(ByVal obj As Object) As Integer _ Implements IComparable.CompareTo If TypeOf obj Is Temperature Then Dim otherTemperature As Temperature = DirectCast(obj, Temperature) Return Me.temperatureF.CompareTo(otherTemperature.temperatureF) Else Throw New ArgumentException("Object is not a Temperature") End If End Function Public Property Fahrenheit() As Double Get Return temperatureF End Get Set(ByVal Value As Double) Me.temperatureF = Value End Set End Property Public Property Celsius() As Double Get Return (temperatureF - 32) * (5/9) End Get Set(ByVal Value As Double) Me.temperatureF = (Value * 9/5) + 32 End Set End Property End Class

Public Module CompareTemperatures Public Sub Main() Dim temperatures As New ArrayList ' Initialize random number generator. Dim rnd As New Random() ' Generate 10 temperatures between 0 and 100 randomly. For ctr As Integer = 1 To 10 Dim degrees As Integer = rnd.Next(0, 100) Dim temp As New Temperature temp.Fahrenheit = degrees temperatures.Add(temp) Next ' Sort ArrayList. temperatures.Sort() For Each temp As Temperature In temperatures Console.WriteLine(temp.Fahrenheit) Next End Sub End Module ' The example displays the following output to the console (individual ' values may vary because they are randomly generated): ' 2 ' 7 ' 16 ' 17 ' 31 ' 37 ' 58 ' 66 ' 72 ' 95 C# using System; using System.Collections; public class Temperature : IComparable { // The temperature value protected double temperatureF; public int CompareTo(object obj) { if(obj is Temperature) { Temperature otherTemperature = (Temperature) obj; return this.temperatureF.CompareTo(otherTemperature.temperatureF); } else { throw new ArgumentException("Object is not a Temperature"); } } public double Fahrenheit

{

get { return this.temperatureF; } set { this.temperatureF = value; }

}

}

public double Celsius { get { return (this.temperatureF - 32) * (5/9); } set { this.temperatureF = (value * 9/5) + 32; } }

public class CompareTemperatures { public static void Main() { ArrayList temperatures = new ArrayList(); // Initialize random number generator. Random rnd = new Random(); // Generate 10 temperatures between 0 and 100 randomly. for (int ctr = 1; ctr <= 10; ctr++) { int degrees = rnd.Next(0, 100); Temperature temp = new Temperature(); temp.Fahrenheit = degrees; temperatures.Add(temp); } // Sort ArrayList. temperatures.Sort(); foreach (Temperature temp in temperatures) Console.WriteLine(temp.Fahrenheit);

} } // The example displays the following output to the console (individual // values may vary because they are randomly generated): // 2 // 7 // 16 // 17 // 31 // 37 // 58 // 66

// //

72 95

Related Documents

70-536 Test Part 2
June 2020 1
Test 2
November 2019 8
Test 2
November 2019 10
Test 2
November 2019 15