Beruflich Dokumente
Kultur Dokumente
Namespace: System.Collections
Assembly: mscorlib (in mscorlib.dll)
Syntax
Visual Basic (Declaration)
<ComVisibleAttribute(True)> _
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
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
End Class
Public Sub CopyTo(ByVal array As Array, ByVal index As Integer) Implements IDictionary.CopyTo
Throw New NotImplementedException()
End Sub
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);
}
// 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.");
}
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 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 Declaration
public event MouseClickedEventHandler MouseClicked;
Declare a basic event
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.
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.
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.
throw;
}
catch
{
// Catches all kinds of exceptions, even when they are not
// CLS-comform, which can appear only when calling
// unmanaged code.
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.
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.
Also, in most cases, you should set the InnerException property (second argument of the constructor) for
further reference.
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.
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.
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
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
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 programming-
advance 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
}
}
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
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\.
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.
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 CLR-
Excception 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.
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.
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.
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
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 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.
// create a property
public int Hour
{
get { return hour; }
set { hour = value; }
}You then access the properties in the following manner:
// Increment iHour
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.
// create a property
public int Hour
{
get { return hour; }
internal set { hour = value; }
}
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:
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.
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.
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:
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 string Id
{
get { return id; }
set { }
}
}
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.
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:
}
}
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:
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<T> 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
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
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.
myQueue.Enqueue(data);
myList.Add(data); //Enqueue
Note: To protect the Queue from abuse the enumerator only allows read operations.
Unlike the IEnumerator (returned by Collections.Queue) the Queue<T>.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;
myQueue.Enqueue(1);
myQueue.Enqueue(2);
myQueue.Enqueue(3);
myQueue.Enqueue(4);
queuePrint(myQueue);
myQueue.Dequeue();
myQueue.Dequeue();
queuePrint(myQueue);
}
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.
C#
[SerializableAttribute]
[ComVisibleAttribute(false)]
public class Queue<T> : IEnumerable<T>, 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
' 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 second copy, with duplicates and nulls:")
For Each number As String In queueCopy2
Console.WriteLine(number)
Next
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");
// Create a copy of the queue, using the ToArray method and the
// constructor that accepts an IEnumerable<T>.
Queue<string> queueCopy = new Queue<string>(numbers.ToArray());
// 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);
Console.WriteLine("\nqueueCopy.Contains(\"four\") = {0}",
queueCopy.Contains("four"));
Console.WriteLine("\nqueueCopy.Clear()");
queueCopy.Clear();
Console.WriteLine("\nqueueCopy.Count = {0}", queueCopy.Count);
}
}
one
two
three
four
five
Dequeuing 'one'
Peek at next item to dequeue: two
Dequeuing 'two'
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.
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.
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.
Module Example
Sub Main
' 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 second copy, with duplicates and nulls:")
For Each number As String In queueCopy2
Console.WriteLine(number)
Next
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");
// Create a copy of the queue, using the ToArray method and the
// constructor that accepts an IEnumerable<T>.
Queue<string> queueCopy = new Queue<string>(numbers.ToArray());
// 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);
Console.WriteLine("\nqueueCopy.Clear()");
queueCopy.Clear();
Console.WriteLine("\nqueueCopy.Count = {0}", queueCopy.Count);
}
}
one
two
three
four
five
Dequeuing 'one'
Peek at next item to dequeue: two
Dequeuing 'two'
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.
myStack.Push(data);
Note: To protect the stack from abuse the enumerator only allows read operations.
Unlike the IEnumerator (returned by Collections.Stack) the Stack<T>.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;
myStack.Push(1);
myStack.Push(2);
myStack.Push(3);
myStack.Push(4);
stackPrint(myStack);
myStack.Pop();
myStack.Pop();
stackPrint(myStack);
}
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.
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> _
<ComVisibleAttribute(False)> _
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<T> : IEnumerable<T>, 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.
Module Example
Sub Main
' 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 second copy, with duplicates and nulls:")
For Each number As String In stack3
Console.WriteLine(number)
Next
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");
// Create a copy of the stack, using the ToArray method and the
// constructor that accepts an IEnumerable<T>.
Stack<string> stack2 = new Stack<string>(numbers.ToArray());
// 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);
Console.WriteLine("\nstack2.Contains(\"four\") = {0}",
stack2.Contains("four"));
Console.WriteLine("\nstack2.Clear()");
stack2.Clear();
Console.WriteLine("\nstack2.Count = {0}", stack2.Count);
}
}
five
four
three
two
one
Popping 'five'
Peek at next item to destack: four
Popping 'four'
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.
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.
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.
Module Example
Sub Main
' 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 second copy, with duplicates and nulls:")
For Each number As String In stack3
Console.WriteLine(number)
Next
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");
// Create a copy of the stack, using the ToArray method and the
// constructor that accepts an IEnumerable<T>.
Stack<string> stack2 = new Stack<string>(numbers.ToArray());
// 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);
Console.WriteLine("\nstack2.Contains(\"four\") = {0}",
stack2.Contains("four"));
Console.WriteLine("\nstack2.Clear()");
stack2.Clear();
Console.WriteLine("\nstack2.Count = {0}", stack2.Count);
}
}
five
four
three
two
one
Popping 'five'
Peek at next item to destack: four
Popping 'four'
stack2.Contains("four") = False
stack2.Clear()
stack2.Count = 0
*/
Generic interfaces
ICollection
IList
IDictionary
IComparable
IComparer
IEqualityComparer
IEnumerable
IEnumerator
IEnumerator<T> 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:
//...
}
Generic types
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;
Now imagine what would happen if you pushed a string on the Stack as in the following code;
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;
You can use parameterization not only for classes but also for interfaces, structs, methods and delegates.
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.
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
public class LinkedList<K,T> { ... }The following are all open constructed types:
LinkedList<K,T> myList_1;
LinkedList<int,T> myList_2;
LinkedList<K,string> 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<K,T> { ... }The following are all closed constructed types:
LinkedList<int,string> myList_1;
LinkedList<int,object> myList_2;
LinkedList<object,string> myList_3;
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 : <base class name> The type argument, T, must be or derive from the specified base class.
where T : <interface name> 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<T>
{
private List<T> myList = new List<T>();
}
Generic interfaces
With generic classes it is preferable to use generic interfaces, such as IComparable<T> 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:
// Standard Interface
public interface IPrint
{
void Print();
}
// Generic Interface
public interface MyGenericInterface<T> where T : IPrint
{
void Run(T t);
}
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 delegate void UpdateAnimal<T>(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.
while (items.MoveNext())
{
updater(items.Current);
}
}
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<Cat> catList = new Animals<Cat>();
catList.Add(new Cat("Tinkerbelle", 6));
catList.Add(new Cat("Felix", 3));
catList.Add(new Cat("Whiskers", 10));
catList.Add(new Cat("Tailz", 14));
// Cats
catList.Print();
Console.WriteLine("---------------------------");
catList.UpdateAnimals(new UpdateAnimal<Cat>(UpdateCatAge));
catList.Print();
Console.WriteLine("===========================");
// Dogs
dogList.Print();
Console.WriteLine("---------------------------");
dogList.UpdateAnimals(new UpdateAnimal<Dog>(UpdateDogAge));
dogList.Print();
}
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);
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<int> list1 = new List<int>();
// 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.
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 Description
where T: struct 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 : <base class name> The type argument must be or derive from the specified base class.
where T : <interface name> 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<T> 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 int ID
{
get { return id; }
set { id = value; }
}
}
public Node(T t)
{
next = null;
data = t;
}
public T Data
{
get { return data; }
set { data = value; }
}
}
public T FindFirstOccurrence(string s)
{
Node current = head;
T t = null;
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<T> where T : Employee, IEmployee, System.IComparable<T>, 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>(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<T> constraint and implement
that interface in any class that will be used to construct the generic class.
C#
class Base { }
class Test<T, U>
where U : struct
where T : Base, new() { }
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.
C#
class List<T>
{
void Add<U>(List<U> 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<T, U, V> 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.
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<T> class shows how to use the default keyword. For more
information, see Generics Overview.
C#
public class GenericList<T>
{
private class Node
{
//...
//...
public T GetNext()
{
T temp = default(T);
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<T>
{
void Add(T input) { }
}
class TestGenericList
{
private class ExampleClass { }
static void Main()
{
// Declare a list of type int.
GenericList<int> list1 = new GenericList<int>();
Generics Overview
Use generic types to maximize code reuse, type safety, and performance.
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.
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.
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.
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:
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.
Because generic classes can serve as base classes, the same design considerations apply here as with non-
generic classes. See the rules about inheriting from generic base classes later in this topic.
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<T>, client code can reference the class either by specifying a type argument, to create a
closed constructed type (Node<int>). Alternatively, it can leave the type parameter unspecified, for example
when you specify a generic base class, to create an open constructed type (Node<T>). Generic classes can
inherit from concrete, closed constructed, or open constructed base classes:
C#
class BaseNode { }
class BaseNodeGeneric<T> { }
// concrete type
class NodeConcrete<T> : BaseNode { }
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<int> { }
//Generates an error
//class Node2 : BaseNodeGeneric<T> {}
//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<T, U> { }
//No error
class Node4<T> : BaseNodeMultiple<T, int> { }
//No error
class Node5<T, U> : BaseNodeMultiple<T, U> { }
//Generates an error
//class Node6<T> : BaseNodeMultiple<T, U> {}
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<T> where T : System.IComparable<T>, new() { }
class SpecialNodeItem<T> : NodeItem<T> where T : System.IComparable<T>, new() { }
Generic types can use multiple type parameters and constraints, as follows:
C#
class SuperKeyType<K, V, U>
where U : System.IComparable<U>
where V : new()
{}
Open constructed and closed constructed types can be used as method parameters:
C#
void Swap<T>(List<T> list1, List<T> 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<BaseClass>, you will get a
compile-time error if you try to provide a List<DerivedClass>.
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>(T item);
public static void Notify(int i) { }
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<int> 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>
{
T[] items;
int index;
Code that references the delegate must specify the type argument of the containing class, as follows:
C#
private static void DoWork(float[] items) { }
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, U>(T sender, U eventArgs);
class Stack<T>
{
public class StackEventArgs : System.EventArgs { }
public event StackEventHandler<Stack<T>, StackEventArgs> stackEvent;
class SampleClass
{
public void HandleStackChange<T>(Stack<T> stack, Stack<T>.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<T> class that derives from the GenericList<T>
class. For more information, see Introduction to Generics (C# Programming Guide). SortedList<T> adds the
constraint where T : IComparable<T>. This enables the BubbleSort method in SortedList<T> to use the
generic CompareTo method on list elements. In this example, list elements are a simple class, Person, that
implements IComparable<Person>.
C#
//Type parameter T in angle brackets.
public class GenericList<T> : System.Collections.Generic.IEnumerable<T>
{
protected Node head;
protected Node current = null;
do
{
Node previous = null;
Node current = head;
swapped = false;
class Program
{
static void Main()
{
//Declare and instantiate a new generic SortedList class.
//Person is the type argument.
SortedList<Person> list = new SortedList<Person>();
int[] ages = new int[] { 45, 19, 28, 23, 18, 9, 108, 72, 30, 35 };
C#
class Stack<T> where T : System.IComparable<T>, IEnumerable<T>
{
}
C#
interface IDictionary<K, V>
{
}
C#
interface IMonth<T> { }
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.
C#
interface IBaseInterface<T> { }
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<T> { }
interface IBaseInterface2<T, U> { }
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<T>(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;
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<T>
{
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<T> in the following example.
C#
class GenericList<T>
{
// CS0693
void SampleMethod<T>() { }
}
class GenericList2<T>
{
//No warning
void SampleMethod<U>() { }
}
Use constraints to enable more specialized operations on type parameters in methods. This version of
Swap<T>, now named SwapIfGreater<T>, can only be used with type arguments that implement
IComparable<(Of <(T>)>).
C#
void SwapIfGreater<T>(ref T lhs, ref T rhs) where T : System.IComparable<T>
{
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<T>() { }
void DoWork<T, U>() { }
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<int> 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<int> code:
C#
Stack<int> stackOne = new Stack<int>();
Stack<int> stackTwo = new Stack<int>();
However, suppose that another Stack<(Of <(T>)>) class with a different value type such as a long or a user-
defined 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<Customer> 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<Order> orders = new Stack<Order>();
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<Customer>();
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<T> 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).
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.
csc generics.cs
generics
C#
GenericList<float> list1 = new GenericList<float>();
GenericList<ExampleClass> list2 = new GenericList<ExampleClass>();
GenericList<ExampleStruct> list3 = new GenericList<ExampleStruct>();
In each of these instances of GenericList<T>, 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).
C#
public interface ISessionChannel<TSession> { /*...*/ }
public delegate TOutput Converter<TInput, TOutput>(TInput from);
public class List<T> { /*...*/ }
Consider using T as the type parameter name for types with one single letter type parameter.
C#
public int IComparer<T>() { return 0; }
public delegate bool Predicate<T>(T item);
public struct Nullable<T> where T : struct { /*...*/ }
C#
public interface ISessionChannel<TSession>
{
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 return type of the public method GetNext and the Data property in the nested Node class.
Note that T is available to the nested Node class. When GenericList<T> is instantiated with a concrete type,
for example as a GenericList<int>, each occurrence of T will be replaced with int.
C#
// type parameter T in angle brackets
public class GenericList<T>
{
// 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;
}
The following code example shows how client code uses the generic GenericList<T> 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<int> list = new GenericList<int>();
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 Description
Comparer<(Of <(T>)>) 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 Description
Dictionary<(Of <(TKey, TValue>)>)..::.Enumerator 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.
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";
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> _
<ComVisibleAttribute(True)> _
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.
Module Example
Sub Main()
' If a key does not exist, setting the default Item property
' for that key adds a new key/value pair.
openWith("doc") = "winword.exe"
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();
if (!openWith.ContainsKey("doc"))
{
Console.WriteLine("Key \"doc\" is not found.");
}
}
}
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.
*/
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.
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;
Console.WriteLine("(Nicola)");
printInfo(nicola);
Console.WriteLine("(NicolaClone)");
printInfo(nicolaClone);
Console.WriteLine("(Nicola)");
printInfo(nicola);
Console.WriteLine("(NicolaClone)");
printInfo(nicolaClone);
}
(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.
To demonstrate this further, a shallow change can be done—for example: changing the person’s name.
Console.WriteLine("(Nicola)");
printInfo(nicola);
Console.WriteLine("(NicolaClone)");
printInfo(nicolaClone);
Console.WriteLine("(Nicola)");
printInfo(nicola);
Console.WriteLine("(NicolaClone)");
printInfo(nicolaClone);
}
Notice how the name has changed. Although a string is a reference type it has been copied due to it being a
system type.
return Copy;
(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;
/*********************************************************
* 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);
}
/*****************************************************************
* 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;
/*********************************************************
* 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;
}
/******************************************************
* 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:
return Copy;
}
#endregion
}class Job : ICloneable
{
string m_JobName;
Duties m_Duties;
return copy;
}
#endregion
}class Duties: ICloneable
{
string m_DutyA;
string m_DutyB;
#endregion
}
Example
Note that only a slight change had to be made in the way that duties are set due to phasing out the clone-
unfriendly method.
Console.WriteLine("(Nicola)");
printInfo(nicola);
Console.WriteLine("(NicolaClone)");
printInfo(nicolaClone);
Console.WriteLine("(Nicola)");
printInfo(nicola);
Console.WriteLine("(NicolaClone)");
printInfo(nicolaClone);
}
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)
<ComVisibleAttribute(True)> _
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
C#
using System;
class MyBaseClass {
public static string CompanyName = "My Company";
public int age;
public string name;
}
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.
Method syntax
int CompareTo (T comparee)where comparee is an object to be compared with this object.
Usage
Simple equality (==) example
class Vector
{
private double m_X, double m_Y, double m_Z;
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:
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:
magnitudeThis = Math.Sqrt(magnitudeThis);
magnitudeThat = Math.Sqrt(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.
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;
Double magnitudeThis = 0;
Double magnitudeThat = 0;
int returnValue = 0;
magnitudeThis = Math.Sqrt(magnitudeThis);
magnitudeThat = Math.Sqrt(magnitudeThat);
return returnValue;
}
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)
<ComVisibleAttribute(True)> _
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
C#
using System;
using System.Collections;
// Sort ArrayList.
temperatures.Sort();