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.
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 {
} 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); }
} /* 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);
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"));
} /* 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