Вы находитесь на странице: 1из 107

Category:Exam 70-536 Study Guide: Skill Set 1

Microsoft .NET Framework, ASP.NET, Visual C# (CSharp, C Sharp, C-Sharp) Developer


Training, Visual Studio

Articles in category "Exam 70-536 Study Guide: Skill Set 1"


There are 52 articles in this category.

 ArrayList
 Attributes
 BitArray class
 Boxing and Unboxing
 Class Members
 Collection interfaces
 CollectionBase classes
 Comparer class
 Constructors and Destructors
 Copy Constructors
 Declaring Classes
 Delegate
 DictionaryBase classes
 Event
 Exam 70-536 Study Guide: Skill Set 1
 Exception classes
 Fields and Properties
 Generic Lists
 Generic Queue
 Generic Stack
 Generic interfaces
 Generic types
 Hashtable class
 ICloneable
 IComparable
 IConvertible
 IDisposable
 IEquatable
 IFormattable
 INullableValue
 Implement .NET Framework interfaces
 Interfaces and Abstract Classes
 Iterators
 Manage a group of associated data using collections
 Manage data in a .NET Framework application
 Nested Classes
 Nullable type
 Queue class
 Reference types
 SortedList class
 Stack class
 Template:Exam 70-536 Study Guide Skill Set 1-4
 TypeForwardedToAttribute
 Typecasting
 Use events and delegates
 Use generic collections
 Use specialized collections
 Value types
 Value vs Reference
 const, static and readonly
 enum
 struct

ArrayList

Description
An ArrayList is an array that can dynamically grow and shrink.

Members
Here are some of the common members of the ArrayList class. For a complete listing see
the MSDN Reference at the bottom of the page.

Properties
Capacity - Gets or sets the number of elements that the ArrayList can contain.
Count - Gets the number of elements contained in an ArrayList object.
IsFixedSize - Gets a value indicating whether a ArrayList object has a fixed size. A collection
with a fixed size does not allow the addition or removal of elements after the collection is
created, but does allow the modification of existing elements.
Item - Gets or sets the element at the specified index.
Methods
Add(value) - Adds an object to the end of the ArrayList.

Yep
Because the ArrayList is untyped, you should use List<T> unless backwards compatibility is
needed.

Code Examples
Using an arraylist to store numbers
// Create a new ArrayList
ArrayList numbers = new ArrayList();

// Add some numbers to the list


numbers.Add( 7 );
numbers.Add( 21 );

// Get the numbers out of the list


// Notice a cast is required because
// ArrayList only contain objects (untyped)
// This also performs an unboxing operation
int numA = (int)numbers[0];
int numB = (int)numbers[1];

Bad example of mixing the content of an ArrayList


// Create a new ArrayList
ArrayList mixedList = new ArrayList();

// Add some numbers to the list


mixedList.Add( 7 );
mixedList.Add( 21 );

// Add some strings to the list


mixedList.Add( "Hello" );
mixedList.Add( "This is going to be a problem" );

// Now try to iterate the list


// This will throw an exception
foreach( string text in mixedList){
//...
}

ArrayList Class

Implements the IList interface using an array whose size is dynamically increased as
required.

Namespace: System.Collections
Assembly: mscorlib (in mscorlib.dll)

C#
[SerializableAttribute]
[ComVisibleAttribute(true)]
public class ArrayList : IList, ICollection,
IEnumerable, ICloneable

The following code example shows how to create and initialize an ArrayList and how to print
out its values.

vb
Imports System
Imports System.Collections
Imports Microsoft.VisualBasic
Public Class SamplesArrayList
Public Shared Sub Main()
' Creates and initializes a new ArrayList.
Dim myAL As New ArrayList()
myAL.Add("Hello")
myAL.Add("World")
myAL.Add("!")
'Displays the properties and values of the ArrayList.
Console.WriteLine("myAL")
Console.WriteLine(" Count: {0}", myAL.Count)
Console.WriteLine(" Capacity: {0}", myAL.Capacity)
Console.Write(" Values:")
PrintValues(myAL)
End Sub
Public Shared Sub PrintValues(myList As IEnumerable)
Dim obj As [Object]
For Each obj In myList
Console.Write(" {0}", obj)
Next obj
Console.WriteLine()
End Sub 'PrintValues
End Class

‘This code produces output similar to the following:


'
‘myAL
' Count: 3
' Capacity: 4
' Values: Hello World !
c#
using System;
using System.Collections;
public class SamplesArrayList {

public static void Main() {

// Creates and initializes a new ArrayList.


ArrayList myAL = new ArrayList();
myAL.Add("Hello");
myAL.Add("World");
myAL.Add("!");

// Displays the properties and values of the ArrayList.


Console.WriteLine( "myAL" );
Console.WriteLine( " Count: {0}", myAL.Count );
Console.WriteLine( " Capacity: {0}", myAL.Capacity );
Console.Write( " Values:" );
PrintValues( myAL );
}
public static void PrintValues( IEnumerable myList ) {
foreach ( Object obj in myList )
Console.Write( " {0}", obj );
Console.WriteLine();
}
}

/*
This code produces output similar to the following:

myAL
Count: 3
Capacity: f
Values: Hello World !

*/

Attributes
An attribute is a mechanism to add declarative information to code elements (types,
members, assemblies or modules) beyond the usual predefined keywords. They are saved
with the metadata of the object and can be used to describe the code at runtime or to
affect application behavior at run time through the use of reflection.

An attribute must derive from the System.Attribute class, either directly or indirectly. This
means that as well as the numerous predefined attributes that are in the .NET FCL, you can
define your own custom attributes.

Attribute usage and syntax


The convention of adding the suffix "Attribute" to all attribute names is adopted to
distinguish them from other items in the .NET Framework. However, it is not necessary to
specify the attribute suffix when using attributes in code. For example, [DllImport] is
equivalent to using [System.DllImportAttribute], but DllImportAttribute is the attribute's
actual name in the System namespace of the .NET Framework.

Attributes can be placed on almost any target element (though a specific attribute might
restrict the types of declarations on which it is valid). Syntactically, an attribute is specified
by placing the name of the attribute, enclosed in square brackets, in front of the declaration
of the entity to which it applies. For example, a method with the attribute DllImport is
declared like this:

[DllImport("cards.dll")]
public static extern bool cdtInit
(ref int width, ref int height );Where "cards.dll" is the name of the dll that is being
imported into the application and cdtInit is the name of the method within the dll.

Positional parameters
Positional parameters are specified first. Any positional parameters must be specified in a
certain order and cannot be omitted. For example, if we look at the method above, there is
one specified parameter which is the name of the dll file.

Positional parameters are defined in the constructor of the class, so in this instance, the
constructor of the DllImport attribute looks like this:

public DllImportAttribute ( string dllName )


{
// ...
}

Named parameters
Named parameters are optional and can be specified in any order after any positional
parameters. These are defined as public properties in the class. If we take a look at a
couple of the properties of the DllImportAttribute class, we can show this in action.

SetLastError - Indicates whether the callee calls the SetLastError Win32 API function before
returning from the attributed method.
EntryPoint - Indicates the name or ordinal of the DLL entry point to be called.
For example, calling the Beep method located in "kernel32.dll" may look like this:

[DllImport("Kernel32.dll", SetLastError = true, EntryPoint = "Beep")]


static extern Boolean Beep(UInt32 frequency, UInt32 duration);The positional property is
specified first with the two named parameters following it. Equally the attributes could look
like this:

[DllImport("Kernel32.dll", EntryPoint = "Beep", SetLastError = true)]


static extern Boolean Beep(UInt32 frequency, UInt32 duration);This is equally as valid as
the first example. The positional property is specified first with the two named parameters
following it.

Using multiple attributes


More than one attribute can be associated with an element if it is required. There are two
methods of implementing this, stacking or combining. Here is an example of stacking two
attributes:

bool aMethod([In][Out]ref double x);And here is an example of combining the same two
attributes:

bool aMethod([In,Out]ref double x);


Target type
In certain situations, the target of an attribute (that is, the entity to which the attribute
applies) appears to be ambiguous. Usually, the type that immediately follows the attribute
declaration is what the attribute is assigned to, so there is no need to supply the target.
However, you may want to assign the target in your attribute declaration for clarity and
readability. For example, in the following method declaration, the SomeAttribute attribute
could apply to the method or to the methods return value:

[SomeAttribute("Hello")]
public string MyMethod(string aString)
{
return aString;
} This sort of situation arises frequently when marshalling. To resolve the ambiguity, C#
has a set of default targets for each kind of declaration, which can be overridden by
explicitly specifying attribute targets.

[method: SomeAttribute] // applies to method


public string MyMethod(string aString)

[return: SomeAttribute] // applies to return value


public string MyMethod(string aString)

[SomeAttribute] // default: applies to method


public string MyMethod(string aString)Note that this is independent of the targets on which
SomeAttribute is defined to be valid; that is, even if SomeAttribute were defined to apply
only to return values, the return target would still have to be specified. In other words, the
compiler will not use AttributeUsage information to resolve ambiguous attribute targets.

The syntax for attribute targets is as follows:

[Target: attribute list]The table below lists all declarations where attributes are allowed; for
each declaration, the possible targets for attributes on the declaration are listed in the
second column. The targets in bold are the default values.

Declaration Possible Targets


assembly assembly
module module
class type
struct type
interface type
enum type
delegate type, return
method method, return
parameter param
field field
property —indexer property
property — get accessor method, return
property — set accessor method, param, return
event — field event, field, method
event — property event, property
event — add method, param
event — remove method, param
Predefined attributes
The .NET Framework comes with almost 200 predefined attributes, used for purposes such
as debugging, design-time, compiler/runtime control behavior, and much more. The
following are some of the more common predefined attributes:

Predefined .NET
Valid Targets Description
Attribute

AttributeUsage Class Specifies the valid usage of another attribute class.

Indicates whether a program element is compliant with the Common


CLSCompliant All
Language Specification (CLS).

Indicates that the compiler can ignore any calls to this method if the
Conditional Method
associated string is defined.

Specifies the DLL location that contains the implementation of an external


DllImport Method
method.

Indicates that the default threading model for an application is multithreaded


MTAThread Method (Main)
apartment (MTA).

NonSerialized Field
Applies to fields of a class flagged as Serializable; specifies that
these fields won’t be serialized.

All except Assembly,


Marks an element obsolete—in other words, it informs the user that the
Obsolete Module, Parameter, and
element will be removed in future versions of the product.
Return

Allows a single parameter to be implicitly treated as a params (array)


ParamArray Parameter
parameter.

Class, struct, enum,


Serializable delegate
Specifies that all public and private fields of this type can be serialized.

STAThread Method (Main) Indicates that the default threading model for an application is STA.

Specifies the nature of the data layout of a class or struct, such as Auto,
StructLayout Class, struct
Explicit, or Sequential.
Implements thread-local storage (TLS)—in other words, the given static field
ThreadStatic Field (static) isn’t shared across multiple threads and each thread has its own copy of the
static field.

Custom attributes
You can create custom attributes to add extra information to your code.

Creating a Custom Attribute Class


Each attribute is extended from the System.Attribute class. System.Attribute is an abstract
class defining the intrinsic services of an attribute. The MSDN documentation gives an
example for creating an Author attribute, so that the author of a piece of code can be
recorded.

[System.AttributeUsage(System.AttributeTargets.Class |
System.AttributeTargets.Struct)]
public class AuthorAttribute : System.Attribute
{
private string name;
public double version;
public AuthorAttribute(string name)
{
this.name = name;
version = 1.0;
}
} When using the attribute, the code:

[Author ("H. Ackerman", version = 1.1)]


class SampleClassis conceptually equivalent to this:

AuthorAttribute anonymousAuthorObject = new AuthorAttribute("H. Ackerman");


anonymousAuthorObject.version = 1.1;
class SampleClass The sample class code is simply supplied in the MSDN article without
much explanation but let’s look at what each part of the code does.

Assigning the AttributeUsageAttribute to your class


When you are defining your own attribute class, you can control the manner in which it is
used by placing an AttributeUsageAttribute on your attribute class. The supplied code shows
the shortened version of the class name (as discussed at the beginning of this section), with
the inclusion on the namespace. The namespace is not needed if you include "using
System;

AttributeUsage has three parameters: ValidOn, AllowMultiple and Inherited.


The ValidOn parameter is positional and accepts values from the AttributeTargets
enumerator. This parameter is used to restrict the use of your attribute to the code types
you specify. The default value is AttributeTargets.All, but you can combine several
AttributeTargets values using a bitwise OR operation to get the desired combination of valid
program elements. The members of AttributeTargets enum are:

All - Attribute can be applied to any application element.


Assembly - Attribute can be applied to an assembly.
Class - Attribute can be applied to a class.
Constructor - Attribute can be applied to a constructor.
Delegate - Attribute can be applied to a delegate.
Enum - Attribute can be applied to an enumeration.
Event - Attribute can be applied to an event.
Field - Attribute can be applied to a field.
GenericParameter - Attribute can be applied to a generic parameter.
Interface - Attribute can be applied to an interface.
Method - Attribute can be applied to a method.
Module - Attribute can be applied to a module (.exe or .dll).
Parameter - Attribute can be applied to a parameter.
Property - Attribute can be applied to a property.
ReturnValue - Attribute can be applied to a return value.
Struct - Attribute can be applied to a structure; that is, a value type.
* Reference AttributeTargets Enumeration (MSDN)
The sample above (AuthorAttribute) indicates that the attribute can be applied to classes
and structures only.

AllowMultiple is a named parameter which specifies whether the indicated attribute can be
specified more than once for a given program element. The default value is false. To allow
the above sample to be used more than once, this parameter needs to be set to true.

[System.AttributeUsage(System.AttributeTargets.Class |
System.AttributeTargets.Struct,
AllowMultiple = true) // multiuse attribute
] The sample in the MSDN article can be seen in use thus:

[Author ("H. Ackerman", version = 1.1)]


[Author ("M. Knott", version = 1.2)]
class SampleClass
{
// H. Ackerman's code goes here...
// M. Knott's code goes here...
} Inherited is a named parameter which specifies whether the indicated attribute can be
inherited by derived classes and overriding members. The default value is true.

Creating positional parameters


Positional parameters are defined in the constructor of the class. So in the MSDN sample
class, there is one positional parameter called name which is passed in as a parameter to
the constructor of the class.

Creating named parameters


Named parameters are defined as public fields or properties in the class. So in the MSDN
sample class, there is one named parameter called version.
Reflecting on attributes
Once you have mastered the ability of creating attributes, it is useful to use them in the
code. This can be achieved through the use of the GetCustomAttributes method of the
Attributes class.

The GetCustomAttributes method returns an array of Attribute objects. As the


AuthorAttribute has AllowMultiple set to true, it is possible to define the same attribute
multiple times on an element. Also, not all elements will have the attribute defined that is
being searching for, so GetCustomAttributes can return an array with multiple results, or an
empty array.

In order to return all of the attributes members, the AuthorAttribute class needs a small
modification to return the positional parameter.

public string Name


{
get { return name; }
} The GetCustomAttributes method has many variations, see MSDN for more information.
In order to get all attributes attached to a type, only one argument is required. This is a
boolean value telling the framework whether it should look at the types that this class
derives from.

Here is a sample Console application that uses the AuthorAttribute class.

[Author("J.R.R. Tolkein")]
public class FirstClass
{
}
[Author("R. Feist")]
[Author("J. Herbert", version = 2.0)]
[Author("P. Martin", version = 2.1)]
public class SecondClass
{
}
// No Author attribute
public class ThirdClass
{
}

class Program
{
static void Main(string[] args)
{
PrintAuthorInfo(typeof(FirstClass));
PrintAuthorInfo(typeof(SecondClass));
PrintAuthorInfo(typeof(ThirdClass));
}

private static void PrintAuthorInfo(System.Type t)


{
System.Console.WriteLine("Author information for {0}", t);

object[] attrs = t.GetCustomAttributes(false); // reflection

foreach (AuthorAttribute a in attrs)


{
Console.WriteLine("{0}, version {1:f}", a.Name, a.version);
}
}
}
The PrintAuthorInfo method uses reflection to obtain the parameters of the AuthorAttribute.

BitArray class

Description
The BitArray class manages a compact array of bit values. These bit values are boolean in
nature, having the value true (1) or false (0).

Members
Here are some of the common members of the BitArray class. For a complete listing see the
MSDN Reference at the bottom of the page.

Properties
Count - Gets the number of elements contained in the BitArray.
IsReadOnly - Gets a value indicating whether the BitArray is read-only.
Item - Gets or sets the value of the bit at a specific position in the BitArray.
Length - Gets or sets the number of elements in the BitArray.
[edit]Methods
And(BitArray) - Performs the bitwise AND operation on the elements in the current BitArray
against the corresponding elements in the specified BitArray.
CopyTo(Array,index) - Copies the entire BitArray to a compatible one-dimensional Array,
starting at the specified index of the target array.
Get(position) - Gets the value of the bit at a specific position in the BitArray.
Not() - Inverts all the bit values in the current BitArray, so that elements set to true are
changed to false, and elements set to false are changed to true.
Or(BitArray) - Performs the bitwise OR operation on the elements in the current BitArray
against the corresponding elements in the specified BitArray.
Set(position,value) - Sets the bit at a specific position in the BitArray to the specified value.
SetAll(value) - Sets all bits in the BitArray to the specified value.
Xor(BitArray) - Performs the bitwise exclusive OR operation on the elements in the current
BitArrayagainst the corresponding elements in the specified BitArray.
Size and Indexing
The size of a BitArray is set implicitly or explicitly when you create a new one, or by altering
its Length property. If you shorten a BitArray, bits are truncated from the high-order end. If
you lengthen a BitArray, false bits are added to the high-order end.

Elements in a BitArray are accessed using an integer index, which is zero-based. If you try
to index past the end of the BitArray, an ArgumentException is thrown.

Code Examples
Creating BitArrays
BitArray myBitArray = new BitArray( 5 );Creates a BitArray of length 5 with all values set to
false.
BitArray myBitArray = new BitArray( 5, false );Creates a BitArray of length 5 with all values
set to false.
BitArray myBitArray = new BitArray( 5, true );Creates a BitArray of length 5 with all values
set to true.
byte[] myBytes = new byte[5] { 1, 2, 3, 4, 5 };
BitArray myBitArray = new BitArray( myBytes );Creates a BitArray of length 40 with bit
pattern equal to the binary equivalent of each number in the byte array (8 bits per byte).
bool[] myBools = new bool[5] { true, false, true, true, false };
BitArray myBitArray = new BitArray( myBools );Creates a BitArray of length 5 with bit
pattern equal to the bool array.
int[] myInts = new int[5] { 6, 7, 8, 9, 10 };
BitArray myBitArray = new BitArray( myInts );Creates a BitArray of length 160 with bit
pattern equal to the binary equivalent of each number in the int array (32 bits per int).

Set Value - Convert value to BitArray


Most of the time when using the BitArray class, you simply want to set a value. On
initialization this can be done with.

byte[] value = {0x11};


BitArray myBits = new BitArray(value);But how can the value be changed later in the code?
Unfortunately no method exists in the BitArray class to do this. Therefore you must
implement your own method such as the following:

BitArray myBits = new BitArray(8); //define the size

//setting a value
for (byte x = 0; x < myBits.Count; x++)
{
myBits[x] = (((value >> x) & 0x01) == 0x01) ? true : false;
}This type of code can be done in many convoluted ways. The use of a shift operation, bit
mask operation and short hand if statement simplify this into just 2 easily understandable
lines of code.

Get Value - Convert BitArray to value


Another missing feature of the BitArray class is to get the value of the array.
byte value = 0x00;

for (byte x = 0; x < bArray.Count; x++)


{
value |= (byte) ((bArray[x] == true) ? (0x01 << x) : 0x00);
}

BitArray Class

Manages a compact array of bit values, which are represented as Booleans, where true
indicates that the bit is on (1) and false indicates the bit is off (0).

Namespace: System.Collections
Assembly: mscorlib (in mscorlib.dll)

Syntax:
C#
[SerializableAttribute]
[ComVisibleAttribute(true)]
public sealed class BitArray : ICollection,
IEnumerable, ICloneable

Examples
The following code example shows how to create and initialize a BitArray and how to print
out its values.
using System;
using System.Collections;
public class SamplesBitArray {

public static void Main() {

// Creates and initializes several BitArrays.


BitArray myBA1 = new BitArray( 5 );

BitArray myBA2 = new BitArray( 5, false );

byte[] myBytes = new byte[5] { 1, 2, 3, 4, 5 };


BitArray myBA3 = new BitArray( myBytes );

bool[] myBools = new bool[5] { true, false, true, true, false };


BitArray myBA4 = new BitArray( myBools );

int[] myInts = new int[5] { 6, 7, 8, 9, 10 };


BitArray myBA5 = new BitArray( myInts );
// Displays the properties and values of the BitArrays.
Console.WriteLine( "myBA1" );
Console.WriteLine( " Count: {0}", myBA1.Count );
Console.WriteLine( " Length: {0}", myBA1.Length );
Console.WriteLine( " Values:" );
PrintValues( myBA1, 8 );

Console.WriteLine( "myBA2" );
Console.WriteLine( " Count: {0}", myBA2.Count );
Console.WriteLine( " Length: {0}", myBA2.Length );
Console.WriteLine( " Values:" );
PrintValues( myBA2, 8 );

Console.WriteLine( "myBA3" );
Console.WriteLine( " Count: {0}", myBA3.Count );
Console.WriteLine( " Length: {0}", myBA3.Length );
Console.WriteLine( " Values:" );
PrintValues( myBA3, 8 );

Console.WriteLine( "myBA4" );
Console.WriteLine( " Count: {0}", myBA4.Count );
Console.WriteLine( " Length: {0}", myBA4.Length );
Console.WriteLine( " Values:" );
PrintValues( myBA4, 8 );

Console.WriteLine( "myBA5" );
Console.WriteLine( " Count: {0}", myBA5.Count );
Console.WriteLine( " Length: {0}", myBA5.Length );
Console.WriteLine( " Values:" );
PrintValues( myBA5, 8 );
}

public static void PrintValues( IEnumerable myList, int myWidth ) {


int i = myWidth;
foreach ( Object obj in myList ) {
if ( i <= 0 ) {
i = myWidth;
Console.WriteLine();
}
i--;
Console.Write( "{0,8}", obj );
}
Console.WriteLine();
}

}
/*
This code produces the following output.

myBA1
Count: 5
Length: 5
Values:
False False False False False
myBA2
Count: 5
Length: 5
Values:
False False False False False
myBA3
Count: 40
Length: 40
Values:
True False False False False False False False
False True False False False False False False
True True False False False False False False
False False True False False False False False
True False True False False False False False
myBA4
Count: 5
Length: 5
Values:
True False True True False
myBA5
Count: 160
Length: 160
Values:
False True True False False False False False
False False False False False False False False
False False False False False False False False
False False False False False False False False
True True True False False False False False
False False False False False False False False
False False False False False False False False
False False False False False False False False
False False False True False False False False
False False False False False False False False
False False False False False False False False
False False False False False False False False
True False False True False False False False
False False False False False False False False
False False False False False False False False
False False False False False False False False
False True False True False False False False
False False False False False False False False
False False False False False False False False
False False False False False False False False
*/

Inheritance Hierarchy
System..::.Object
System.Collections..::.BitArray

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.
This implementation does not provide a synchronized (thread safe) wrapper for a BitArray.
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.

BitArray Members
Manages a compact array of bit values, which are represented as Booleans, where true
indicates that the bit is on (1) and false indicates the bit is off (0).
The BitArray type exposes the following members.

Constructors Name Description


BitArray Overloaded. Initializes a new instance of the BitArray class whose capacity and
initial values can be specified.

Methods Name Description


And Performs the bitwise AND operation on the elements in the current
BitArray against the corresponding elements in the specified
BitArray.
Clone Creates a shallow copy of the BitArray.
CopyTo Copies the entire BitArray to a compatible one-dimensional Array,
starting at the specified index of the target array.
Equals Determines whether the specified Object is equal to the current
Object. (Inherited from Object.)
Finalize Allows an Object to attempt to free resources and perform other
cleanup operations before the Object is reclaimed by garbage
collection. (Inherited from Object.)
Get Gets the value of the bit at a specific position in the BitArray.
GetEnumerator Returns an enumerator that iterates through the BitArray.
GetHashCode Serves as a hash function for a particular type. (Inherited from
Object.)
GetType Gets the Type of the current instance. (Inherited from Object.)
MemberwiseClone Creates a shallow copy of the current Object. (Inherited from
Object.)
Not Inverts all the bit values in the current BitArray, so that elements
set to true are changed to false, and elements set to false are
changed to true.
Or Performs the bitwise OR operation on the elements in the current
BitArray against the corresponding elements in the specified
BitArray.
Set Sets the bit at a specific position in the BitArray to the specified value.
SetAll Sets all bits in the BitArray to the specified value.
ToString Returns a String that represents the current Object. (Inherited from
Object.)
Xor Performs the bitwise exclusive OR operation on the elements in the
current BitArray against the corresponding elements in the specified
BitArray.
Extension Methods
Name Description
AsQueryable Converts an IEnumerable to an IQueryable. (Defined by Queryable.)
Cast Converts the elements of an IEnumerable to the specified type.
(Defined by Enumerable.)
OfType Filters the elements of an IEnumerable based on a specified type.
(Defined by Enumerable.)

Properties
Name Description
Count Gets the number of elements contained in the BitArray.
IsReadOnly Gets a value indicating whether the BitArray is read-only.
IsSynchronized Gets a value indicating whether access to the BitArray is synchronized
(thread safe).
Item Gets or sets the value of the bit at a specific position in the BitArray.
Length Gets or sets the number of elements in the BitArray.
SyncRoot Gets an object that can be used to synchronize access to the BitArray.

Boxing and Unboxing


Boxing is the process of turning a value type object into a reference type object.
Whenever a value type object is boxed, its value is copied into a new object on the heap
and the reference to that object is stored.

int number = 10;

// The following causes a box operation


// numRef will refer to an object on the
// heap which contains a copy of number (10)
object numRef = number;

// Next unbox the value by casting it to


// the appropriate type
int numberB = (int) numRef;

Unboxing is not type safe. It requires a cast because the compiler cannot determine the
type of the object. If the object is not the correct type, it will cause an exception during
the cast operation.
Large numbers of boxing and unboxing operations can become a performance problem. It
should be avoided if possible. In particular, Generic types do not depend on boxing
operations and they should be used whenever possible. Also, generic types maintain type
safety.

Class Members
Once a class is created it must be populated with data and methods in order to make it
useful as a programming construct. The data and methods which act upon the data are
referred to as members.

Members
There are several types of members that a class can have. These are:

Fields - instances of objects that are considered part of a class, normally holding class
data.
Properties - methods on a class that are accessed as if they were fields on that class. A
property can provide protection for a class field to keep it from being changed without the
object's knowledge. For a more detailed understanding see Fields and Properties.
Methods - these define the actions that a class can perform by actioning a series of
statements. Methods can take parameters that provide input data, and can return output
data through parameters. Methods can also return a value directly, without using a
parameter.
Events - a way of providing notifications about occurrences, such as button clicks or the
successful completion of a method, to other objects. Events are defined and triggered
using delegates. (See the 70-536 entry for Events and check out the article by Jeff Sudeth
and read the sample chapter "Delegates and Events" by Jesse Liberty).
Delegates - a type safe container of one or more function pointers. (See the 70-536 entry
for Delegates and check out the article by Jeff Sudeth).
Operators - these are terms or symbols such as +, *, <, and so on that perform
operations on operands. Operators can be redefined to perform operations on custom data
types.
Indexers - these allow an object to be indexed in a manner similar to arrays.
Constructors - methods that are called when the object is first created. They are often
used to initialize the object's data.
Destructors - methods that are called by the runtime execution engine when the object is
about to be removed from memory. They are generally used to make sure that any
resources which need to be released are handled appropriately.
Constants - data members that are known at compile time.
Modifiers
Each type of modifier may or may not be available to a member. The modifiers may
include:

abstract - indicates that a class is intended only to be a base class of other classes.

extern - used to declare a method that is implemented externally (as in a DLL file).

new - hides a member inherited from a base class.

override - required to extend or modify the abstract or virtual implementation of an


inherited method, property, indexer, or event.

readonly - fields that are read-only and are initialized at declaration or in a constructor.

sealed - overrides a method in a base class, but itself cannot be overridden further in any
derived class.

static – a member that doesn't belong to an instance of the class, but belongs to the class
itself.

virtual - used to modify a method, property, indexer or event declaration, and allow it to
be overridden in a derived class.

volatile - fields that are modifiable by the environment, a separate thread, or hardware.

Accessibility
public - any item in the current assembly or any assembly that references the class, can
access this member.

protected - access is limited to the containing class or types derived from the containing
class.

internal - any item in the current assembly can access this member.

protected internal - access is limited to the current assembly or types derived from the
containing class.

private - access is limited to the containing class.

Members (C# Programming Guide)

Classes and structs have members that represent their data and behavior. A class's
members include all the members declared in the class, along with all members (except
constructors and destructors) declared in all classes in its inheritance hierarchy. Private
members in base classes are inherited but are not accessible from derived classes.
The following table lists the kinds of members a class or struct may contain:

Member Description
Fields Fields are variables declared at class scope. A field may be a built-in
numeric type or an instance of another class. For example, a calendar
class may have a field that contains the current date.
Constants Constants are fields or properties whose value is set at compile time and
cannot be changed.
Properties Properties are methods on a class that are accessed as if they were
fields on that class. A property can provide protection for a class field to
keep it from being changed without the knowledge of the object.
Methods Methods define the actions that a class can perform. Methods can take
parameters that provide input data, and can return output data through
parameters. Methods can also return a value directly, without using a
parameter.
Events Events provide notifications about occurrences, such as button clicks or
the successful completion of a method, to other objects. Events are
defined and triggered by using delegates. For more information, see
Events and Delegates.
Operators Overloaded operators are considered class members. When you
overload an operator, you define it as a public static method in a class.
The predefined operators (+, *, <, and so on) are not considered
members. For more information, see Overloadable Operators (C#
Programming Guide).
Indexers Indexers enable an object to be indexed in a manner similar to arrays.
Constructors Constructors are methods that are called when the object is first
created. They are often used to initialize the data of an object.
Destructors Destructors are used very rarely in C#. They are methods that are
called by the runtime execution engine when the object is about to be
removed from memory. They are generally used to make sure that any
resources which must be released are handled appropriately.
Nested Types Nested types are types declared within another type. Nested types are
often used to describe objects that are used only by the types that
contain them.

abstract
The abstract modifier indicates that the thing being modified has a missing or incomplete
implementation. The abstract modifier can be used with classes, methods, properties,
indexers, and events. Use the abstract modifier in a class declaration to indicate that a
class is intended only to be a base class of other classes. Members marked as abstract, or
included in an abstract class, must be implemented by classes that derive from the
abstract class.

Example
abstract class ShapesClass
{
abstract public int Area();
}
class Square : ShapesClass
{
int side = 0;

public Square(int n)
{
side = n;
}
// Area method is required to avoid
// a compile-time error.
public override int Area()
{
return side * side;
}

static void Main()


{
Square sq = new Square(12);
Console.WriteLine("Area of the square = {0}", sq.Area());
}

interface I
{
void M();
}
abstract class C : I
{
public abstract void M();
}

}
// Output: Area of the square = 144

Abstract classes have the following features:

An abstract class cannot be instantiated.

An abstract class may contain abstract methods and accessors.

It is not possible to modify an abstract class with the sealed (C# Reference) modifier
because the two modifers have opposite meanings. The sealed modifier prevents a class
from being inherited and the abstract modifier requires a class to be inherited.

A non-abstract class derived from an abstract class must include actual implementations
of all inherited abstract methods and accessors.
Use the abstract modifier in a method or property declaration to indicate that the method
or property does not contain implementation.

Abstract methods have the following features:

An abstract method is implicitly a virtual method.

Abstract method declarations are only permitted in abstract classes.

Because an abstract method declaration provides no actual implementation, there is no


method body; the method declaration simply ends with a semicolon and there are no curly
braces ({ }) following the signature. For example:

public abstract void MyMethod();


The implementation is provided by an overriding methodoverride (C# Reference), which is
a member of a non-abstract class.

It is an error to use the static or virtual modifiers in an abstract method declaration.

Abstract properties behave like abstract methods, except for the differences in declaration
and invocation syntax.

It is an error to use the abstract modifier on a static property.

An abstract inherited property can be overridden in a derived class by including a property


declaration that uses the override modifier.

For more information about abstract classes, see Abstract and Sealed Classes and Class
Members (C# Programming Guide) and Abstract Class Design.

An abstract class must provide implementation for all interface members.

An abstract class that implements an interface might map the interface methods onto
abstract methods. For example:

C#
interface I
{
void M();
}
abstract class C : I
{
public abstract void M();
}
In this example, the class DerivedClass is derived from an abstract class BaseClass. The
abstract class contains an abstract method, AbstractMethod, and two abstract properties,
X and Y.

abstract class BaseClass // Abstract class


{
protected int _x = 100;
protected int _y = 150;
public abstract void AbstractMethod(); // Abstract method
public abstract int X { get; }
public abstract int Y { get; }
}

class DerivedClass : BaseClass


{
public override void AbstractMethod()
{
_x++;
_y++;
}

public override int X // overriding property


{
get
{
return _x + 10;
}
}

public override int Y // overriding property


{
get
{
return _y + 10;
}
}

static void Main()


{
DerivedClass o = new DerivedClass();
o.AbstractMethod();
Console.WriteLine("x = {0}, y = {1}", o.X, o.Y);
}
}
// Output: x = 111, y = 161
In the preceding example, if you attempt to instantiate the abstract class by using a
statement like this:

BaseClass bc = new BaseClass(); // Error


you will get an error saying that the compiler cannot create an instance of the abstract
class 'BaseClass'.

extern (C# Reference)

The extern modifier is used to declare a method that is implemented externally. A


common use of the extern modifier is with the DllImport attribute when you are using
Interop services to call into unmanaged code. In this case, the method must also be
declared as static, as shown in the following example:

[DllImport("avifil32.dll")]
private static extern void AVIFileInit();

The extern keyword can also define an external assembly alias, which makes it possible to
reference different versions of the same component from within a single assembly.

It is an error to use the abstract (C# Reference) and extern modifiers together to modify
the same member. Using the extern modifier means that the method is implemented
outside the C# code, whereas using the abstract modifier means that the method
implementation is not provided in the class.

Example:
In this example, the program receives a string from the user and displays it inside a
message box. The program uses the MessageBox method imported from the User32.dll
library.

//using System.Runtime.InteropServices;
class ExternTest
{
[DllImport("User32.dll", CharSet=CharSet.Unicode)]
public static extern int MessageBox(int h, string m, string c, int type);

static int Main()


{
string myString;
Console.Write("Enter your message: ");
myString = Console.ReadLine();
return MessageBox(0, myString, "My Message Box", 0);
}

}
This example creates a DLL from a C program that is invoked from within the C# program
in the next example.

// cmdll.c
// Compile with: /LD
int __declspec(dllexport) SampleMethod(int i)
{
return i*10;
}
This example uses two files, CM.cs and Cmdll.c, to demonstrate extern. The C file is the
external DLL created in Example 2 that is invoked from within the C# program.
// cm.cs
using System;
using System.Runtime.InteropServices;
public class MainClass
{
[DllImport("Cmdll.dll")]
public static extern int SampleMethod(int x);

static void Main()


{
Console.WriteLine("SampleMethod() returns {0}.", SampleMethod(5));
}
}
SampleMethod() returns 50.

Remarks
To build the project:

Compile Cmdll.c to a DLL by using the Visual C++ command line:

cl /LD Cmdll.c

Compile CM.cs using the command line:

csc CM.cs

This will create the executable file CM.exe. When you run this program, SampleMethod
will pass the value 5 to the DLL file, which returns the value multiplied by 10.

extern (C# Reference)

The extern modifier is used to declare a method that is implemented externally. A


common use of the extern modifier is with the DllImport attribute when you are using
Interop services to call into unmanaged code. In this case, the method must also be
declared as static, as shown in the following example:
[DllImport("avifil32.dll")]
private static extern void AVIFileInit();

Note:
The extern keyword can also define an external assembly alias, which makes it possible to
reference different versions of the same component from within a single assembly. For
more information, see extern alias (C# Reference).

It is an error to use the abstract (C# Reference) and extern modifiers together to modify
the same member. Using the extern modifier means that the method is implemented
outside the C# code, whereas using the abstract modifier means that the method
implementation is not provided in the class.

Note:
The extern keyword has more limited uses than in C++. To compare with the C++
keyword, see Using extern to Specify Linkage in the C++ Language Reference.

Example
In this example, the program receives a string from the user and displays it inside a
message box. The program uses the MessageBox method imported from the User32.dll
library.

//using System.Runtime.InteropServices;
class ExternTest
{
[DllImport("User32.dll", CharSet=CharSet.Unicode)]
public static extern int MessageBox(int h, string m, string c, int type);

static int Main()


{
string myString;
Console.Write("Enter your message: ");
myString = Console.ReadLine();
return MessageBox(0, myString, "My Message Box", 0);
}

This example creates a DLL from a C program that is invoked from within the C# program
in the next example.

// cmdll.c
// Compile with: /LD
int __declspec(dllexport) SampleMethod(int i)
{
return i*10;
}
This example uses two files, CM.cs and Cmdll.c, to demonstrate extern. The C file is the
external DLL created in Example 2 that is invoked from within the C# program.

// cm.cs
using System;
using System.Runtime.InteropServices;
public class MainClass
{
[DllImport("Cmdll.dll")]
public static extern int SampleMethod(int x);

static void Main()


{
Console.WriteLine("SampleMethod() returns {0}.", SampleMethod(5));
}
}

SampleMethod() returns 50.


Remarks
To build the project:

Compile Cmdll.c to a DLL by using the Visual C++ command line:

cl /LD Cmdll.c

Compile CM.cs using the command line:

csc CM.cs

This will create the executable file CM.exe. When you run this program, SampleMethod
will pass the value 5 to the DLL file, which returns the value multiplied by 10.

new Modifier (C# Reference)

When used as a modifier, the new keyword explicitly hides a member inherited from a
base class. When you hide an inherited member, the derived version of the member
replaces the base-class version. Although you can hide members without the use of the
new modifier, the result is a warning. If you use new to explicitly hide a member, it
suppresses this warning and documents the fact that the derived version is intended as a
replacement.

To hide an inherited member, declare it in the derived class by using the same name, and
modify it with the new modifier. For example:

public class BaseC


{
public int x;
public void Invoke() { }
}
public class DerivedC : BaseC
{
new public void Invoke() { }
}

In this example, BaseC.Invoke is hidden by DerivedC.Invoke. The field x is not affected


because it is not hidden by a similar name.

Name hiding through inheritance takes one of the following forms:

A constant, field, property, or type introduced in a class or struct hides all base class
members with the same name.

A method introduced in a class or struct hides properties, fields, and types, with the same
name, in the base class. It also hides all base class methods with the same signature.

An indexer introduced in a class or struct hides all base class indexers with the same
signature.

It is an error to use both new and override on the same member because the two
modifiers have mutually exclusive meanings. The new modifier creates a new member
with the same name and causes the original member to become hidden. The override
modifier extends the implementation for an inherited member.

Using the new modifier in a declaration that does not hide an inherited member generates
a warning.

Example
In this example, a base class, BaseC, and a derived class, DerivedC, use the same field
name x, which hides the value of the inherited field. The example demonstrates the use of
the new modifier. It also demonstrates how to access the hidden members of the base
class by using their fully qualified names.

public class BaseC


{
public static int x = 55;
public static int y = 22;
}

public class DerivedC : BaseC


{
// Hide field 'x'.
new public static int x = 100;

static void Main()


{
// Display the new value of x:
Console.WriteLine(x);

// Display the hidden value of x:


Console.WriteLine(BaseC.x);

// Display the unhidden member y:


Console.WriteLine(y);
}
}
/*
Output:
100
55
22
*/

In this example, a nested class hides a class that has the same name in the base class.
The example demonstrates how to use the new modifier to eliminate the warning message
and how to access the hidden class members by using their fully qualified names.

public class BaseC


{
public class NestedC
{
public int x = 200;
public int y;
}
}

public class DerivedC : BaseC


{
// Nested type hiding the base type members.
new public class NestedC
{
public int x = 100;
public int y;
public int z;
}

static void Main()


{
// Creating an object from the overlapping class:
NestedC c1 = new NestedC();

// Creating an object from the hidden class:


BaseC.NestedC c2 = new BaseC.NestedC();

Console.WriteLine(c1.x);
Console.WriteLine(c2.x);
}
}
/*
Output:
100
200
*/

If you remove the new modifier, the program will still compile and run, but you will get
the following warning:

Copy Code
The keyword new is required on 'MyDerivedC.x' because it hides inherited member
'MyBaseC.x'.
You can also use the new modifier to modify a nested type if the nested type is hiding
another type, as demonstrated in the following example.

new Modifier (C# Reference)

When used as a modifier, the new keyword explicitly hides a member inherited from a
base class. When you hide an inherited member, the derived version of the member
replaces the base-class version. Although you can hide members without the use of the
new modifier, the result is a warning. If you use new to explicitly hide a member, it
suppresses this warning and documents the fact that the derived version is intended as a
replacement.

To hide an inherited member, declare it in the derived class by using the same name, and
modify it with the new modifier. For example:

public class BaseC


{
public int x;
public void Invoke() { }
}
public class DerivedC : BaseC
{
new public void Invoke() { }
}

In this example, BaseC.Invoke is hidden by DerivedC.Invoke. The field x is not affected


because it is not hidden by a similar name.

Name hiding through inheritance takes one of the following forms:

A constant, field, property, or type introduced in a class or struct hides all base class
members with the same name.

A method introduced in a class or struct hides properties, fields, and types, with the same
name, in the base class. It also hides all base class methods with the same signature.

An indexer introduced in a class or struct hides all base class indexers with the same
signature.

It is an error to use both new and override on the same member because the two
modifiers have mutually exclusive meanings. The new modifier creates a new member
with the same name and causes the original member to become hidden. The override
modifier extends the implementation for an inherited member.

Using the new modifier in a declaration that does not hide an inherited member generates
a warning.

Example
In this example, a base class, BaseC, and a derived class, DerivedC, use the same field
name x, which hides the value of the inherited field. The example demonstrates the use of
the new modifier. It also demonstrates how to access the hidden members of the base
class by using their fully qualified names.

public class BaseC


{
public static int x = 55;
public static int y = 22;
}

public class DerivedC : BaseC


{
// Hide field 'x'.
new public static int x = 100;

static void Main()


{
// Display the new value of x:
Console.WriteLine(x);
// Display the hidden value of x:
Console.WriteLine(BaseC.x);

// Display the unhidden member y:


Console.WriteLine(y);
}
}
/*
Output:
100
55
22
*/

In this example, a nested class hides a class that has the same name in the base class.
The example demonstrates how to use the new modifier to eliminate the warning message
and how to access the hidden class members by using their fully qualified names.

public class BaseC


{
public class NestedC
{
public int x = 200;
public int y;
}
}

public class DerivedC : BaseC


{
// Nested type hiding the base type members.
new public class NestedC
{
public int x = 100;
public int y;
public int z;
}

static void Main()


{
// Creating an object from the overlapping class:
NestedC c1 = new NestedC();

// Creating an object from the hidden class:


BaseC.NestedC c2 = new BaseC.NestedC();
Console.WriteLine(c1.x);
Console.WriteLine(c2.x);
}
}
/*
Output:
100
200
*/

If you remove the new modifier, the program will still compile and run, but you will get
the following warning:

The keyword new is required on 'MyDerivedC.x' because it hides inherited member


'MyBaseC.x'.
You can also use the new modifier to modify a nested type if the nested type is hiding
another type, as demonstrated in the following example

override (C# Reference)

The override modifier is required to extend or modify the abstract or virtual


implementation of an inherited method, property, indexer, or event.

Example
In this example, the Square class must provide an overridden implementation of Area
because Area is inherited from the abstract ShapesClass:

abstract class ShapesClass


{
abstract public int Area();
}
class Square : ShapesClass
{
int side = 0;

public Square(int n)
{
side = n;
}
// Area method is required to avoid
// a compile-time error.
public override int Area()
{
return side * side;
}
static void Main()
{
Square sq = new Square(12);
Console.WriteLine("Area of the square = {0}", sq.Area());
}

interface I
{
void M();
}
abstract class C : I
{
public abstract void M();
}

}
// Output: Area of the square = 144

An override method provides a new implementation of a member that is inherited from a


base class. The method that is overridden by an override declaration is known as the
overridden base method. The overridden base method must have the same signature as
the override method. For information about inheritance, see Inheritance (C# Programming
Guide).

You cannot override a non-virtual or static method. The overridden base method must be
virtual, abstract, or override.

An override declaration cannot change the accessibility of the virtual method. Both the
override method and the virtual method must have the same access level modifier.

You cannot use the new, static, virtual, or abstract modifiers to modify an override
method.

An overriding property declaration must specify exactly the same access modifier, type,
and name as the inherited property, and the overridden property must be virtual,
abstract, or override.

For more information about how to use the override keyword, see Versioning with the
Override and New Keywords (C# Programming Guide) and Knowing when to use Override
and New Keywords.

This example defines a base class named Employee, and a derived class named
SalesEmployee. The SalesEmployee class includes an extra property, salesbonus, and
overrides the method CalculatePay in order to take it into account.

class TestOverride
{
public class Employee
{
public string name;

// Basepay is defined as protected, so that it may be


// accessed only by this class and derrived classes.
protected decimal basepay;

// Constructor to set the name and basepay values.


public Employee(string name, decimal basepay)
{
this.name = name;
this.basepay = basepay;
}

// Declared virtual so it can be overridden.


public virtual decimal CalculatePay()
{
return basepay;
}
}

// Derive a new class from Employee.


public class SalesEmployee : Employee
{
// New field that will affect the base pay.
private decimal salesbonus;

// The constructor calls the base-class version, and


// initializes the salesbonus field.
public SalesEmployee(string name, decimal basepay,
decimal salesbonus) : base(name, basepay)
{
this.salesbonus = salesbonus;
}

// Override the CalculatePay method


// to take bonus into account.
public override decimal CalculatePay()
{
return basepay + salesbonus;
}
}

static void Main()


{
// Create some new employees.
SalesEmployee employee1 = new SalesEmployee("Alice",
1000, 500);
Employee employee2 = new Employee("Bob", 1200);

Console.WriteLine("Employee4 " + employee1.name +


" earned: " + employee1.CalculatePay());
Console.WriteLine("Employee4 " + employee2.name +
" earned: " + employee2.CalculatePay());
}
}
/*
Output:
Employee4 Alice earned: 1500
Employee4 Bob earned: 1200
*/

readonly (C# Reference)

The readonly keyword is a modifier that you can use on fields. When a field declaration
includes a readonly modifier, assignments to the fields introduced by the declaration can
only occur as part of the declaration or in a constructor in the same class.

Example
In this example, the value of the field year cannot be changed in the method ChangeYear,
even though it is assigned a value in the class constructor:

class Age
{
readonly int _year;
Age(int year)
{
_year = year;
}
void ChangeYear()
{
//_year = 1967; // Compile error if uncommented.
}
}

You can assign a value to a readonly field only in the following contexts:

When the variable is initialized in the declaration, for example:

public readonly int y = 5;


For an instance field, in the instance constructors of the class that contains the field
declaration, or for a static field, in the static constructor of the class that contains the field
declaration. These are also the only contexts in which it is valid to pass a readonly field as
an out or ref parameter.

Note:
The readonly keyword is different from the const keyword. A const field can only be
initialized at the declaration of the field. A readonly field can be initialized either at the
declaration or in a constructor. Therefore, readonly fields can have different values
depending on the constructor used. Also, while a const field is a compile-time constant,
the readonly field can be used for runtime constants as in the following example:

public static readonly uint timeStamp = (uint)DateTime.Now.Ticks;

public class ReadOnlyTest


{
class SampleClass
{
public int x;
// Initialize a readonly field
public readonly int y = 25;
public readonly int z;

public SampleClass()
{
// Initialize a readonly instance field
z = 24;
}

public SampleClass(int p1, int p2, int p3)


{
x = p1;
y = p2;
z = p3;
}
}

static void Main()


{
SampleClass p1 = new SampleClass(11, 21, 32); // OK
Console.WriteLine("p1: x={0}, y={1}, z={2}", p1.x, p1.y, p1.z);
SampleClass p2 = new SampleClass();
p2.x = 55; // OK
Console.WriteLine("p2: x={0}, y={1}, z={2}", p2.x, p2.y, p2.z);
}
}
/*
Output:
p1: x=11, y=21, z=32
p2: x=55, y=25, z=24
*/

In the preceding example, if you use a statement like this:

p2.y = 66; // Error

you will get the compiler error message:

The left-hand side of an assignment must be an l-value

Which is the same error you get when you attempt to assign a value to a constant?

sealed
When applied to a class, the sealed modifier prevents other classes from inheriting from it.
In the following example, class B inherits from class A, but no class can inherit from class
B.

class A {}
sealed class B : A {}
You can also use the sealed modifier on a method or property that overrides a virtual
method or property in a base class. This enables you to allow classes to derive from your
class and prevent them from overriding specific virtual methods or properties.

Example
In the following example, Z inherits from Y but Z cannot override the virtual function F
that is declared in X and sealed in Y.

class X
{
protected virtual void F() { Console.WriteLine("X.F"); }
protected virtual void F2() { Console.WriteLine("X.F2"); }
}
class Y : X
{
sealed protected override void F() { Console.WriteLine("Y.F"); }
protected override void F2() { Console.WriteLine("X.F3"); }
}
class Z : Y
{
// Attempting to override F causes compiler error CS0239.
// protected override void F() { Console.WriteLine("C.F"); }
// Overriding F2 is allowed.
protected override void F2() { Console.WriteLine("Z.F2"); }
}

When you define new methods or properties in a class, you can prevent deriving classes
from overriding them by not declaring them as virtual.

It is an error to use the abstract modifier with a sealed class, because an abstract class
must be inherited by a class that provides an implementation of the abstract methods or
properties.

When applied to a method or property, the sealed modifier must always be used with
override.

Because structs are implicitly sealed, they cannot be inherited.

For more information, see Inheritance (C# Programming Guide).

sealed class SealedClass


{
public int x;
public int y;
}

class SealedTest2
{
static void Main()
{
SealedClass sc = new SealedClass();
sc.x = 110;
sc.y = 150;
Console.WriteLine("x = {0}, y = {1}", sc.x, sc.y);
}
}
// Output: x = 110, y = 150

In the previous example, you might try to inherit from the sealed class by using the
following statement:

class MyDerivedC: SealedClass {} // Error

The result is an error message:

'MyDerivedC' cannot inherit from sealed class 'SealedClass'.

static (C# Reference)


The static modifier can be used with classes, fields, methods, properties, operators,
events, and constructors, but it cannot be used with indexers, destructors, or types other
than classes. The static modifier on a class means that the class cannot be instantiated,
and that all of its members are static. A static member has one version regardless of how
many instances of its enclosing type are created. For more information, see Static Classes
and Static Class Members (C# Programming Guide).

Example
The following class is declared as static and contains only static methods:

static class CompanyEmployee


{
public static void DoSomething() { /*...*/ }
public static void DoSomethingElse() { /*...*/ }
}

A constant or type declaration is implicitly a static member.

A static member cannot be referenced through an instance. Instead, it is referenced


through the type name. For example, consider the following class:

public class MyBaseC


{
public struct MyStruct
{
public static int x = 100;
}
}

To refer to the static member x, use the fully qualified name (unless it is accessible from
the same scope):

MyBaseC.MyStruct.x
While an instance of a class contains a separate copy of all instance fields of the class,
there is only one copy of each static field.

It is not possible to use this to reference static methods or property accessors.

If the static keyword is applied to a class, all the members of the class must be static.

Classes and static classes may have static constructors. Static constructors are called at
some point between when the program starts and the class is instantiated.

Note:
The static keyword has more limited uses than in C++. To compare with the C++
keyword, see Static (C++).

To demonstrate static members, consider a class that represents a company employee.


Assume that the class contains a method to count employees and a field to store the
number of employees. Both the method and the field do not belong to any instance
employee. Instead they belong to the company class. Therefore, they should be declared
as static members of the class.

This example reads the name and ID of a new employee, increments the employee
counter by one, and displays the information for the new employee and the new number
of employees. For simplicity, this program reads the current number of employees from
the keyboard. In a real application, this information should be read from a file.

public class Employee4


{
public string id;
public string name;

public Employee4()
{
}

public Employee4(string name, string id)


{
this.name = name;
this.id = id;
}

public static int employeeCounter;

public static int AddEmployee()


{
return ++employeeCounter;
}
}

class MainClass : Employee4


{
static void Main()
{
Console.Write("Enter the employee's name: ");
string name = Console.ReadLine();
Console.Write("Enter the employee's ID: ");
string id = Console.ReadLine();

// Create and configure the employee object:


Employee4 e = new Employee4(name, id);
Console.Write("Enter the current number of employees: ");
string n = Console.ReadLine();
Employee4.employeeCounter = Int32.Parse(n);
Employee4.AddEmployee();

// Display the new information:


Console.WriteLine("Name: {0}", e.name);
Console.WriteLine("ID: {0}", e.id);
Console.WriteLine("New Number of Employees: {0}",
Employee4.employeeCounter);
}
}
/*
Input:
Matthias Berndt
AF643G
15
*
Sample Output:
Enter the employee's name: Matthias Berndt
Enter the employee's ID: AF643G
Enter the current number of employees: 15
Name: Matthias Berndt
ID: AF643G
New Number of Employees: 16
*/

This example shows that although you can initialize a static field by using another static
field not yet declared, the results will be undefined until you explicitly assign a value to
the static field.

class Test
{
static int x = y;
static int y = 5;

static void Main()


{
Console.WriteLine(Test.x);
Console.WriteLine(Test.y);

Test.x = 99;
Console.WriteLine(Test.x);
}
}
/*
Output:
0
5
99
*/

virtual (C# Reference)

The virtual keyword is used to modify a method, property, indexer, or event declaration
and allow for it to be overridden in a derived class. For example, this method can be
overridden by any class that inherits it:

public virtual double Area()


{
return x * y;
}
The implementation of a virtual member can be changed by an overriding member in a
derived class. For more information about how to use the virtual keyword, see Versioning
with the Override and New Keywords (C# Programming Guide) and Knowing When to Use
Override and New Keywords (C# Programming Guide).

Remarks
When a virtual method is invoked, the run-time type of the object is checked for an
overriding member. The overriding member in the most derived class is called, which
might be the original member, if no derived class has overridden the member.

By default, methods are non-virtual. You cannot override a non-virtual method.

You cannot use the virtual modifier with the static, abstract, private, or override modifiers.
The following example shows a virtual property:

class MyBaseClass
{
// virtual auto-implemented property. Overrides can only
// provide specialized behavior if they implement get and set accessors.
public virtual string Name { get; set; }

// ordinary virtual property with backing field


private int num;
public virtual int Number
{
get { return num; }
set { num = value; }
}
}
class MyDerivedClass : MyBaseClass
{
private string name;

// Override auto-implemented property with ordinary property


// to provide specialized accessor behavior.
public override string Name
{
get
{
return name;
}
set
{
if (value != String.Empty)
{
name = value;
}
else
{
name = "Unknown";
}
}
}

Virtual properties behave like abstract methods, except for the differences in declaration
and invocation syntax.

It is an error to use the virtual modifier on a static property.

A virtual inherited property can be overridden in a derived class by including a property


declaration that uses the override modifier.

Example
In this example, the Dimensions class contains the two coordinates x, y, and the Area()
virtual method. Different shape classes such as Circle, Cylinder, and Sphere inherit the
Dimensions class, and the surface area is calculated for each figure. Each derived class
has it own override implementation of Area(). The program calculates and displays the
appropriate area for each figure by invoking the appropriate implementation of Area()
according to the object associated with the method.

Notice that the inherited classes Circle, Sphere, and Cylinder are all using constructors
that initialize the base class, for example:
public Cylinder(double r, double h): base(r, h) {}
This is similar to the C++ initialization list.

class TestClass
{
public class Dimensions
{
public const double PI = Math.PI;
protected double x, y;
public Dimensions()
{
}
public Dimensions(double x, double y)
{
this.x = x;
this.y = y;
}

public virtual double Area()


{
return x * y;
}
}

public class Circle : Dimensions


{
public Circle(double r) : base(r, 0)
{
}

public override double Area()


{
return PI * x * x;
}
}

class Sphere : Dimensions


{
public Sphere(double r) : base(r, 0)
{
}

public override double Area()


{
return 4 * PI * x * x;
}
}
class Cylinder : Dimensions
{
public Cylinder(double r, double h) : base(r, h)
{
}

public override double Area()


{
return 2 * PI * x * x + 2 * PI * x * y;
}
}

static void Main()


{
double r = 3.0, h = 5.0;
Dimensions c = new Circle(r);
Dimensions s = new Sphere(r);
Dimensions l = new Cylinder(r, h);
// Display results:
Console.WriteLine("Area of Circle = {0:F2}", c.Area());
Console.WriteLine("Area of Sphere = {0:F2}", s.Area());
Console.WriteLine("Area of Cylinder = {0:F2}", l.Area());
}
}
/*
Output:
Area of Circle = 28.27
Area of Sphere = 113.10
Area of Cylinder = 150.80
*/
volatile (C# Reference)

The volatile keyword indicates that a field might be modified by multiple threads that are
executing at the same time. Fields that are declared volatile are not subject to compiler
optimizations that assume access by a single thread. This ensures that the most up-to-
date value is present in the field at all times.

The volatile modifier is usually used for a field that is accessed by multiple threads without
using the lock statement to serialize access. See How to: Create and Terminate Threads
(C# Programming Guide) for an example of volatile in a multi-threaded scenario.

The volatile keyword can be applied to fields of these types:

Reference types.
Pointer types (in an unsafe context). Note that although the pointer itself can be volatile,
the object that it points to cannot. In other words, you cannot declare a "pointer to
volatile."

Integral types such as sbyte, byte, short, ushort, int, uint, char, float, and bool.

An enum type with an integral base type.

Generic type parameters known to be reference types.

IntPtr and UIntPtr.

The volatile keyword can only be applied to fields of a class or struct. Local variables
cannot be declared volatile.

Example
The following example shows how to declare a public field variable as volatile.

class VolatileTest
{
public volatile int i;

public void Test(int _i)


{
i = _i;
}
}

Collection interfaces
As the name implies, a collection interface is an interface that provides the contract for a
specific collection.

The .NET Framework provides a number of standard collection interfaces:

ICollection - Implemented by all collections


IList - Used by collections that can be indexed
IDictionary - For key/value-based collections such as Hashtable and SortedList
IComparer - Allows custom comparison for purpose of sorting and ordering
IEqualityComparer - Allows custom equality comparisons for collections that depend on
equality but not order (like Hashtable)
IKeyComparer - Replaced by IEqualityComparer since .NET 2.0 beta 2
IHashCodeProvider - Replaced by IEqualityComparer since .NET 2.0 beta 2
IEnumerable - Provides the Enumerator for a collection
IEnumerator - Iterates over a collection and supports the foreach loop
IDictionaryEnumerator - An enumerator that enumerates a dictionary and add support for
accessing the key and value of the current item.
Contents
1 ICollection
2 IList
3 IDictionary
4 IComparer
5 IEqualityComparer
6 IKeyComparer
7 IHashCodeProvider
8 IEnumerable
9 IEnumerator
10 IDictionaryEnumerator

ICollection
ICollection extends IEnumerable. It provides size and synchronization members in
addition to enumeration.

IList
IList extends ICollection. It allows access to the items of a collection by their index.

IDictionary
IDictionary extends ICollection. It allows access to the items of a collection by their key.

IComparer
Allows custom comparison for the purposes of sorting and ordering.

IEqualityComparer
Allows custom equality comparisons for collections that depend on equality but not order
(like Hashtable)

IKeyComparer
Replaced by IEqualityComparer since .NET 2.0 beta 2

IHashCodeProvider
Replaced by IEqualityComparer since .NET 2.0 beta 2

IEnumerable
IEnumerable allows a class to be enumerated using an enumerator. A class should inherit
from IEnumerable in order to provide an enumerator through the GetEnumerator()
method.

The foreach automatically calls GetEnumerator at the beginning of the loop and then uses
that enumerator to go through the loop.

IEnumerator
An IEnumerator iterates over each item in a collection. It allows access to the current item
and the ability to proceed to the next item. The foreach loop uses an enumerator to go
through each item.

IDictionaryEnumerator
A IDictionaryEnumerator extends IEnumerator. It also adds support for accessing the key
and value of the current item.

CollectionBase Class

Provides the abstract base class for a strongly typed collection.

Namespace: System.Collections
Assembly: mscorlib (in mscorlib.dll)

[SerializableAttribute]
[ComVisibleAttribute(true)]
public abstract class CollectionBase : IList,
ICollection, IEnumerable

Remarks
A CollectionBase instance is always modifiable. See ReadOnlyCollectionBase for a read-
only version of this class.
The capacity of a CollectionBase is the number of elements the CollectionBase can hold.
As elements are added to a CollectionBase, the capacity is automatically increased as
required through reallocation. The capacity can be decreased by setting the Capacity
property explicitly.

Notes to Implementers:
This base class is provided to make it easier for implementers to create a strongly typed
custom collection. Implementers are encouraged to extend this base class instead of
creating their own.

Examples
The following code example implements the CollectionBase class and uses that
implementation to create a collection of Int16 objects.

using System;
using System.Collections;

public class Int16Collection : CollectionBase {

public Int16 this[ int index ] {


get {
return( (Int16) List[index] );
}
set {
List[index] = value;
}
}

public int Add( Int16 value ) {


return( List.Add( value ) );
}

public int IndexOf( Int16 value ) {


return( List.IndexOf( value ) );
}

public void Insert( int index, Int16 value ) {


List.Insert( index, value );
}

public void Remove( Int16 value ) {


List.Remove( value );
}

public bool Contains( Int16 value ) {


// If value is not of type Int16, this will return false.
return( List.Contains( value ) );
}

protected override void OnInsert( int index, Object value ) {


// Insert additional code to be run only when inserting values.
}

protected override void OnRemove( int index, Object value ) {


// Insert additional code to be run only when removing values.
}

protected override void OnSet( int index, Object oldValue, Object newValue ) {
// Insert additional code to be run only when setting values.
}

protected override void OnValidate( Object value ) {


if ( value.GetType() != typeof(System.Int16) )
throw new ArgumentException( "value must be of type Int16.", "value" );
}

public class SamplesCollectionBase {

public static void Main() {


// Create and initialize a new CollectionBase.
Int16Collection myI16 = new Int16Collection();

// Add elements to the collection.


myI16.Add( (Int16) 1 );
myI16.Add( (Int16) 2 );
myI16.Add( (Int16) 3 );
myI16.Add( (Int16) 5 );
myI16.Add( (Int16) 7 );

// Display the contents of the collection using foreach. This is the preferred method.
Console.WriteLine( "Contents of the collection (using foreach):" );
PrintValues1( myI16 );

// Display the contents of the collection using the enumerator.


Console.WriteLine( "Contents of the collection (using enumerator):" );
PrintValues2( myI16 );

// Display the contents of the collection using the Count property and the Item
property.
Console.WriteLine( "Initial contents of the collection (using Count and Item):" );
PrintIndexAndValues( myI16 );

// Search the collection with Contains and IndexOf.


Console.WriteLine( "Contains 3: {0}", myI16.Contains( 3 ) );
Console.WriteLine( "2 is at index {0}.", myI16.IndexOf( 2 ) );
Console.WriteLine();

// Insert an element into the collection at index 3.


myI16.Insert( 3, (Int16) 13 );
Console.WriteLine( "Contents of the collection after inserting at index 3:" );
PrintIndexAndValues( myI16 );

// Get and set an element using the index.


myI16[4] = 123;
Console.WriteLine( "Contents of the collection after setting the element at index 4 to
123:" );
PrintIndexAndValues( myI16 );

// Remove an element from the collection.


myI16.Remove( (Int16) 2 );

// Display the contents of the collection using the Count property and the Item
property.
Console.WriteLine( "Contents of the collection after removing the element 2:" );
PrintIndexAndValues( myI16 );
}

// Uses the Count property and the Item property.


public static void PrintIndexAndValues( Int16Collection myCol ) {
for ( int i = 0; i < myCol.Count; i++ )
Console.WriteLine( " [{0}]: {1}", i, myCol[i] );
Console.WriteLine();
}

// Uses the foreach statement which hides the complexity of the enumerator.
// NOTE: The foreach statement is the preferred way of enumerating the contents of a
collection.
public static void PrintValues1( Int16Collection myCol ) {
foreach ( Int16 i16 in myCol )
Console.WriteLine( " {0}", i16 );
Console.WriteLine();
}

// Uses the enumerator.


// NOTE: The foreach statement is the preferred way of enumerating the contents of a
collection.
public static void PrintValues2( Int16Collection myCol ) {
System.Collections.IEnumerator myEnumerator = myCol.GetEnumerator();
while ( myEnumerator.MoveNext() )
Console.WriteLine( " {0}", myEnumerator.Current );
Console.WriteLine();
}
}

/*
This code produces the following output.

Contents of the collection (using foreach):


1
2
3
5
7

Contents of the collection (using enumerator):


1
2
3
5
7
Initial contents of the collection (using Count and Item):
[0]: 1
[1]: 2
[2]: 3
[3]: 5
[4]: 7

Contains 3: True
2 is at index 1.

Contents of the collection after inserting at index 3:


[0]: 1
[1]: 2
[2]: 3
[3]: 13
[4]: 5
[5]: 7

Contents of the collection after setting the element at index 4 to 123:


[0]: 1
[1]: 2
[2]: 3
[3]: 13
[4]: 123
[5]: 7

Contents of the collection after removing the element 2:


[0]: 1
[1]: 3
[2]: 13
[3]: 123
[4]: 7

*/

ReadOnlyCollectionBase Class

Provides the abstract base class for a strongly typed non-generic read-only collection.

Namespace: System.Collections
Assembly: mscorlib (in mscorlib.dll)

C#
[SerializableAttribute]
[ComVisibleAttribute(true)]
public abstract class ReadOnlyCollectionBase : ICollection,
IEnumerable

Remarks
A ReadOnlyCollectionBase instance is always read-only. See CollectionBase for a
modifiable version of this class.

Notes to Implementers:
This base class is provided to make it easier for implementers to create a strongly typed
read-only custom collection. Implementers are encouraged to extend this base class
instead of creating their own. Members of this base class are protected and are intended
to be used through a derived class only.
This class makes the underlying collection available through the InnerList property, which
is intended for use only by classes that are derived directly from ReadOnlyCollectionBase.
The derived class must ensure that its own users cannot modify the underlying collection.

Examples
The following code example implements the ReadOnlyCollectionBase class.

using System;
using System.Collections;

public class ROCollection : ReadOnlyCollectionBase {

public ROCollection( IList sourceList ) {


InnerList.AddRange( sourceList );
}

public Object this[ int index ] {


get {
return( InnerList[index] );
}
}

public int IndexOf( Object value ) {


return( InnerList.IndexOf( value ) );
}

public bool Contains( Object value ) {


return( InnerList.Contains( value ) );
}

public class SamplesCollectionBase {


public static void Main() {

// Create an ArrayList.
ArrayList myAL = new ArrayList();
myAL.Add( "red" );
myAL.Add( "blue" );
myAL.Add( "yellow" );
myAL.Add( "green" );
myAL.Add( "orange" );
myAL.Add( "purple" );

// Create a new ROCollection that contains the elements in myAL.


ROCollection myCol = new ROCollection( myAL );

// Display the contents of the collection using foreach. This is the preferred method.
Console.WriteLine( "Contents of the collection (using foreach):" );
PrintValues1( myCol );

// Display the contents of the collection using the enumerator.


Console.WriteLine( "Contents of the collection (using enumerator):" );
PrintValues2( myCol );

// Display the contents of the collection using the Count property and the Item
property.
Console.WriteLine( "Contents of the collection (using Count and Item):" );
PrintIndexAndValues( myCol );

// Search the collection with Contains and IndexOf.


Console.WriteLine( "Contains yellow: {0}", myCol.Contains( "yellow" ) );
Console.WriteLine( "orange is at index {0}.", myCol.IndexOf( "orange" ) );
Console.WriteLine();

// Uses the Count property and the Item property.


public static void PrintIndexAndValues( ROCollection myCol ) {
for ( int i = 0; i < myCol.Count; i++ )
Console.WriteLine( " [{0}]: {1}", i, myCol[i] );
Console.WriteLine();
}

// Uses the foreach statement which hides the complexity of the enumerator.
// NOTE: The foreach statement is the preferred way of enumerating the contents of a
collection.
public static void PrintValues1( ROCollection myCol ) {
foreach ( Object obj in myCol )
Console.WriteLine( " {0}", obj );
Console.WriteLine();
}

// Uses the enumerator.


// NOTE: The foreach statement is the preferred way of enumerating the contents of a
collection.
public static void PrintValues2( ROCollection myCol ) {
System.Collections.IEnumerator myEnumerator = myCol.GetEnumerator();
while ( myEnumerator.MoveNext() )
Console.WriteLine( " {0}", myEnumerator.Current );
Console.WriteLine();
}

/*
This code produces the following output.

Contents of the collection (using foreach):


red
blue
yellow
green
orange
purple

Contents of the collection (using enumerator):


red
blue
yellow
green
orange
purple

Contents of the collection (using Count and Item):


[0]: red
[1]: blue
[2]: yellow
[3]: green
[4]: orange
[5]: purple

Contains yellow: True


orange is at index 4.

*/
Comparer class

You must implement the IComparer interface if you want to provide a custom comparison
method in your code:

class MyCustomComparer : IComparer


{
CaseInsensitiveComparer _comparer =
new CaseInsensitiveComparer();

public int Compare(object x, object y)


{
// custom comparison here
return _comparer.Compare(x, y);
}
}
The Compare method should return -1, 0 or 1 (less than zero, zero, more than zero) to
indicate that object x is less than y, equals to y or more than y, respectively.

Then you can use it as parameter invoking the Sort method for any collection you have:
myList.Sort(new MyCustomComparer());

IComparer Interface

Exposes a method that compares two objects.

Namespace: System.Collections
Assembly: mscorlib (in mscorlib.dll)
Syntax

Visual Basic (Declaration)


<ComVisibleAttribute(True)> _
Public Interface IComparer
Visual Basic (Usage)
Dim instance As IComparer

C#
[ComVisibleAttribute(true)]
public interface IComparer

Remarks
This interface is used in conjunction with the Array..::.Sort and Array..::.BinarySearch
methods. It provides a way to customize the sort order of a collection.

The default implementation of this interface is the Comparer class. For the generic version
of this interface, see System.Collections.Generic..::.IComparer<(Of <(T>)>).
Examples
The following code example demonstrates the use of the IComparer interface to sort an
ArrayList object. In this example, the IComparer interface is implemented using the
CaseInsensitiveComparer class to reverse the order of the contents of the ArrayList.

Visual Basic
Imports System
Imports System.Collections
Imports Microsoft.VisualBasic

Public Class SamplesArrayList

Public Class myReverserClass


Implements IComparer

' Calls CaseInsensitiveComparer.Compare with the parameters reversed.


Public Function Compare( ByVal x As Object, ByVal y As Object) As Integer _
Implements IComparer.Compare
Return New CaseInsensitiveComparer().Compare(y, x)
End Function 'IComparer.Compare

End Class 'myReverserClass

Public Shared Sub Main()

' Creates and initializes a new ArrayList.


Dim myAL As New ArrayList()
myAL.Add("The")
myAL.Add("quick")
myAL.Add("brown")
myAL.Add("fox")
myAL.Add("jumps")
myAL.Add("over")
myAL.Add("the")
myAL.Add("lazy")
myAL.Add("dog")

' Displays the values of the ArrayList.


Console.WriteLine("The ArrayList initially contains the following values:")
PrintIndexAndValues(myAL)

' Sorts the values of the ArrayList using the default comparer.
myAL.Sort()
Console.WriteLine("After sorting with the default comparer:")
PrintIndexAndValues(myAL)
' Sorts the values of the ArrayList using the reverse case-insensitive comparer.
Dim myComparer = New myReverserClass()
myAL.Sort(myComparer)
Console.WriteLine("After sorting with the reverse case-insensitive comparer:")
PrintIndexAndValues(myAL)

End Sub 'Main

Public Shared Sub PrintIndexAndValues(myList As IEnumerable)


Dim i As Integer = 0
Dim obj As [Object]
For Each obj In myList
Console.WriteLine(vbTab + "[{0}]:" + vbTab + "{1}", i, obj)
i=i+1
Next obj
Console.WriteLine()
End Sub 'PrintIndexAndValues

End Class 'SamplesArrayList

'This code produces the following output.


'The ArrayList initially contains the following values:
' [0]: The
' [1]: quick
' [2]: brown
' [3]: fox
' [4]: jumps
' [5]: over
' [6]: the
' [7]: lazy
' [8]: dog
'
'After sorting with the default comparer:
' [0]: brown
' [1]: dog
' [2]: fox
' [3]: jumps
' [4]: lazy
' [5]: over
' [6]: quick
' [7]: the
' [8]: The
'
'After sorting with the reverse case-insensitive comparer:
' [0]: the
' [1]: The
' [2]: quick
' [3]: over
' [4]: lazy
' [5]: jumps
' [6]: fox
' [7]: dog
' [8]: brown

C#
using System;
using System.Collections;

public class SamplesArrayList {

public class myReverserClass : IComparer {

// Calls CaseInsensitiveComparer.Compare with the parameters reversed.


int IComparer.Compare( Object x, Object y ) {
return( (new CaseInsensitiveComparer()).Compare( y, x ) );
}

public static void Main() {

// Creates and initializes a new ArrayList.


ArrayList myAL = new ArrayList();
myAL.Add( "The" );
myAL.Add( "quick" );
myAL.Add( "brown" );
myAL.Add( "fox" );
myAL.Add( "jumps" );
myAL.Add( "over" );
myAL.Add( "the" );
myAL.Add( "lazy" );
myAL.Add( "dog" );

// Displays the values of the ArrayList.


Console.WriteLine( "The ArrayList initially contains the following values:" );
PrintIndexAndValues( myAL );

// Sorts the values of the ArrayList using the default comparer.


myAL.Sort();
Console.WriteLine( "After sorting with the default comparer:" );
PrintIndexAndValues( myAL );
// Sorts the values of the ArrayList using the reverse case-insensitive comparer.
IComparer myComparer = new myReverserClass();
myAL.Sort( myComparer );
Console.WriteLine( "After sorting with the reverse case-insensitive comparer:" );
PrintIndexAndValues( myAL );

public static void PrintIndexAndValues( IEnumerable myList ) {


int i = 0;
foreach ( Object obj in myList )
Console.WriteLine( "\t[{0}]:\t{1}", i++, obj );
Console.WriteLine();
}

/*
This code produces the following output.
The ArrayList initially contains the following values:
[0]: The
[1]: quick
[2]: brown
[3]: fox
[4]: jumps
[5]: over
[6]: the
[7]: lazy
[8]: dog

After sorting with the default comparer:


[0]: brown
[1]: dog
[2]: fox
[3]: jumps
[4]: lazy
[5]: over
[6]: quick
[7]: the
[8]: The

After sorting with the reverse case-insensitive comparer:


[0]: the
[1]: The
[2]: quick
[3]: over
[4]: lazy
[5]: jumps
[6]: fox
[7]: dog
[8]: brown
*/

Remarks
This interface is used in conjunction with the Array..::.Sort and Array..::.BinarySearch
methods. It provides a way to customize the sort order of a collection.

The default implementation of this interface is the Comparer class. For the generic version
of this interface, see System.Collections.Generic..::.IComparer<(Of <(T>)>).

Examples
The following code example demonstrates the use of the IComparer interface to sort an
ArrayList object. In this example, the IComparer interface is implemented using the
CaseInsensitiveComparer class to reverse the order of the contents of the ArrayList.

Visual Basic
Imports System
Imports System.Collections
Imports Microsoft.VisualBasic

Public Class SamplesArrayList

Public Class myReverserClass


Implements IComparer

' Calls CaseInsensitiveComparer.Compare with the parameters reversed.


Public Function Compare( ByVal x As Object, ByVal y As Object) As Integer _
Implements IComparer.Compare
Return New CaseInsensitiveComparer().Compare(y, x)
End Function 'IComparer.Compare

End Class 'myReverserClass

Public Shared Sub Main()

' Creates and initializes a new ArrayList.


Dim myAL As New ArrayList()
myAL.Add("The")
myAL.Add("quick")
myAL.Add("brown")
myAL.Add("fox")
myAL.Add("jumps")
myAL.Add("over")
myAL.Add("the")
myAL.Add("lazy")
myAL.Add("dog")

' Displays the values of the ArrayList.


Console.WriteLine("The ArrayList initially contains the following values:")
PrintIndexAndValues(myAL)

' Sorts the values of the ArrayList using the default comparer.
myAL.Sort()
Console.WriteLine("After sorting with the default comparer:")
PrintIndexAndValues(myAL)

' Sorts the values of the ArrayList using the reverse case-insensitive comparer.
Dim myComparer = New myReverserClass()
myAL.Sort(myComparer)
Console.WriteLine("After sorting with the reverse case-insensitive comparer:")
PrintIndexAndValues(myAL)

End Sub 'Main

Public Shared Sub PrintIndexAndValues(myList As IEnumerable)


Dim i As Integer = 0
Dim obj As [Object]
For Each obj In myList
Console.WriteLine(vbTab + "[{0}]:" + vbTab + "{1}", i, obj)
i=i+1
Next obj
Console.WriteLine()
End Sub 'PrintIndexAndValues

End Class 'SamplesArrayList

'This code produces the following output.


'The ArrayList initially contains the following values:
' [0]: The
' [1]: quick
' [2]: brown
' [3]: fox
' [4]: jumps
' [5]: over
' [6]: the
' [7]: lazy
' [8]: dog
'
'After sorting with the default comparer:
' [0]: brown
' [1]: dog
' [2]: fox
' [3]: jumps
' [4]: lazy
' [5]: over
' [6]: quick
' [7]: the
' [8]: The
'
'After sorting with the reverse case-insensitive comparer:
' [0]: the
' [1]: The
' [2]: quick
' [3]: over
' [4]: lazy
' [5]: jumps
' [6]: fox
' [7]: dog
' [8]: brown

C#
using System;
using System.Collections;

public class SamplesArrayList {

public class myReverserClass : IComparer {

// Calls CaseInsensitiveComparer.Compare with the parameters reversed.


int IComparer.Compare( Object x, Object y ) {
return( (new CaseInsensitiveComparer()).Compare( y, x ) );
}

public static void Main() {

// Creates and initializes a new ArrayList.


ArrayList myAL = new ArrayList();
myAL.Add( "The" );
myAL.Add( "quick" );
myAL.Add( "brown" );
myAL.Add( "fox" );
myAL.Add( "jumps" );
myAL.Add( "over" );
myAL.Add( "the" );
myAL.Add( "lazy" );
myAL.Add( "dog" );

// Displays the values of the ArrayList.


Console.WriteLine( "The ArrayList initially contains the following values:" );
PrintIndexAndValues( myAL );

// Sorts the values of the ArrayList using the default comparer.


myAL.Sort();
Console.WriteLine( "After sorting with the default comparer:" );
PrintIndexAndValues( myAL );

// Sorts the values of the ArrayList using the reverse case-insensitive comparer.
IComparer myComparer = new myReverserClass();
myAL.Sort( myComparer );
Console.WriteLine( "After sorting with the reverse case-insensitive comparer:" );
PrintIndexAndValues( myAL );

public static void PrintIndexAndValues( IEnumerable myList ) {


int i = 0;
foreach ( Object obj in myList )
Console.WriteLine( "\t[{0}]:\t{1}", i++, obj );
Console.WriteLine();
}

/*
This code produces the following output.
The ArrayList initially contains the following values:
[0]: The
[1]: quick
[2]: brown
[3]: fox
[4]: jumps
[5]: over
[6]: the
[7]: lazy
[8]: dog

After sorting with the default comparer:


[0]: brown
[1]: dog
[2]: fox
[3]: jumps
[4]: lazy
[5]: over
[6]: quick
[7]: the
[8]: The

After sorting with the reverse case-insensitive comparer:


[0]: the
[1]: The
[2]: quick
[3]: over
[4]: lazy
[5]: jumps
[6]: fox
[7]: dog
[8]: brown
*/

Constructors and Destructors

Constructors
When a class is declared as in the following code, we only say that we want to have an
instance of the class in our program. We have not yet created the class, only that we have
allocated some program memory.

Car FordCapri;To do this we must instantiate an instance of the class, this is done using
the new keyword, as in the following code:

Car FordCapri = new Car();You can see that after the new keyword we called a method
with the same name as the class. This is called its constructor. A constructor is a method
that is invoked upon instantiation of a class, known as "instance constructors". An
instance constructor is a member that implements the actions required to initialize an
instance of a class.

Every constructor has the same defining layout:

[access-modifier] constructor_name (parameters)


{
// constructor body
}The access-modifier is optional and can be private, public, protected or internal. If no
modifier is supplied, then the default is private.

The constructor_name of a constructor must be the same as the name of the class.
A constructor can take zero or more arguments as parameters. A constructor with zero
arguments (that is no-arguments) is known as a default constructor. A class can have
more than one constructor, by giving each constructor a different set of parameters. This
gives the user the ability to initialise the object in more than one way.

The constructor body can be used to initialise the object into a known starting state.

In, general, a constructor’s access modifier is public, this is because the class that is
creating an instance of this class, needs to be able to access the constructor of the class.

public Car()
{
...
}

Static constructors
A static constructor is used to initialize any static data members. It is called automatically
before the first instance is created or any static members are referenced. A static
constructor does not take access modifiers or have parameters and therefore cannot be
called using the new keyword.

Static constructors have the following properties:

A static constructor does not take access modifiers or have parameters.


Accessibility defaults to the same accessibility as the class itself.
A static constructor is called automatically to initialize the class before the first instance is
created or any static members are referenced.
A static constructor cannot be called directly.
A static constructor cannot be overloaded.
A static constructor is not inheritable.

Destructors
Each class also requires a destructor, this is the code that is called to clean up the object
when it has been finished with. However, if you do not provide one, then the Garbage
Collector will deal with freeing up the memory for you. Any object that you create in the
class, should be deleted from the class as a general rule of thumb.

A destructor is defined pretty much in the same way as a constructor, but has a tilde (~)
in front of the method name.

public ~Car()
{
...
}Destructors have the following properties:

Destructors cannot be inherited or overloaded.


Destructors cannot be called. They are invoked automatically.
A destructor does not take modifiers or have parameters.

Note

Empty destructors should not be used. When a class contains a destructor, an entry is
created in the Finalize queue. When the destructor is called, the garbage collector is
invoked to process the queue. If the destructor is empty, this simply results in a needless
loss of performance.
You should only create a destructor if it is really necessary. Otherwise let the memory
management clean up behind you.

Destructors

Destructors are used to destruct instances of classes.

Remarks
Destructors cannot be defined in structs. They are only used with classes.

A class can only have one destructor.

Destructors cannot be inherited or overloaded.

Destructors cannot be called. They are invoked automatically.

A destructor does not take modifiers or have parameters.

For example, the following is a declaration of a destructor for the class Car:

class Car
{
~Car() // destructor
{
// cleanup statements...
}
}

The destructor implicitly calls Finalize on the base class of the object. Therefore, the
previous destructor code is implicitly translated to the following code:

protected override void Finalize()


{
try
{
// Cleanup statements...
}
finally
{
base.Finalize();
}
}
This means that the Finalize method is called recursively for all instances in the
inheritance chain, from the most-derived to the least-derived.

Note:
Empty destructors should not be used. When a class contains a destructor, an entry is
created in the Finalize queue. When the destructor is called, the garbage collector is
invoked to process the queue. If the destructor is empty, this just causes a needless loss
of performance.

The programmer has no control over when the destructor is called because this is
determined by the garbage collector. The garbage collector checks for objects that are no
longer being used by the application. If it considers an object eligible for destruction, it
calls the destructor (if any) and reclaims the memory used to store the object.
Destructors are also called when the program exits.

It is possible to force garbage collection by calling Collect, but most of the time, this
should be avoided because it may create performance issues.

Using Destructors to Release Resources


In general, C# does not require as much memory management as is needed when you
develop with a language that does not target a runtime with garbage collection. This is
because the .NET Framework garbage collector implicitly manages the allocation and
release of memory for your objects. However, when your application encapsulates
unmanaged resources such as windows, files, and network connections, you should use
destructors to free those resources. When the object is eligible for destruction, the
garbage collector runs the Finalize method of the object.

Explicit Release of Resources


If your application is using an expensive external resource, we also recommend that you
provide a way to explicitly release the resource before the garbage collector frees the
object. You do this by implementing a Dispose method from the IDisposable interface that
performs the necessary cleanup for the object. This can considerably improve the
performance of the application. Even with this explicit control over resources, the
destructor becomes a safeguard to clean up resources if the call to the Dispose method
failed.

For more details about cleaning up resources, see the following topics:

Cleaning Up Unmanaged Resources

Implementing a Dispose Method

using Statement (C# Reference)


Example
The following example creates three classes that make a chain of inheritance. The class
First is the base class, Second is derived from First, and Third is derived from Second. All
three have destructors. In Main(), an instance of the most-derived class is created. When
the program runs, notice that the destructors for the three classes are called
automatically, and in order, from the most-derived to the least-derived.

C#
class First
{
~First()
{
System.Diagnostics.Trace.WriteLine("First's destructor is called.");
}
}

class Second : First


{
~Second()
{
System.Diagnostics.Trace.WriteLine("Second's destructor is called.");
}
}

class Third : Second


{
~Third()
{
System.Diagnostics.Trace.WriteLine("Third's destructor is called.");
}
}

class TestDestructors
{
static void Main()
{
Third t = new Third();
}

}
/* Output (to VS Output Window):
Third's destructor is called.
Second's destructor is called.
First's destructor is called.
*/
Instance Constructors

Instance constructors are used to create and initialize any instance member variables
when you use the new expression to create an object of a class. To initialize a static class,
or static variables in a non-static class, you must define a static constructor. For more
information, see Static Constructors (C# Programming Guide).

The following example shows an instance constructor:

class CoOrds
{
public int x, y;

// constructor
public CoOrds()
{
x = 0;
y = 0;
}
}

Note:
For clarity, this class contains public fields. The use of public fields is not a recommended
programming practice because it allows any method anywhere in a program unrestricted
and unverified access to an object's inner workings. Data members should generally be
private, and should be accessed only through class methods and properties.

This instance constructor is called whenever an object based on the CoOrds class is
created. A constructor like this one, which takes no arguments, is called a default
constructor. However, it is often useful to provide additional constructors. For example,
we can add a constructor to the CoOrds class that allows us to specify the initial values for
the data members:

// tcA constructor with two arguments:


public CoOrds(int x, int y)
{
this.x = x;
this.y = y;
}

This allows CoOrd objects to be created with default or specific initial values, like this:

CoOrds p1 = new CoOrds();


CoOrds p2 = new CoOrds(5, 3);
If a class does not have a default constructor, one is automatically generated and default
values are used to initialize the object fields, for example, an int is initialized to 0. For
more information on default values, see Default Values Table (C# Reference). Therefore,
because the CoOrds class default constructor initializes all data members to zero, it can be
removed altogether without changing how the class works. A complete example using
multiple constructors is provided in Example 1 later in this topic, and an example of an
automatically generated constructor is provided in Example 2.

Instance constructors can also be used to call the instance constructors of base classes.
The class constructor can invoke the constructor of the base class through the initializer,
as follows:

class Circle : Shape


{
public Circle(double radius)
: base(radius, 0)
{
}
}

In this example, the Circle class passes values representing radius and height to the
constructor provided by Shape from which Circle is derived. A complete example using
Shape and Circle appears in this topic as Example 3.

Example 1
The following example demonstrates a class with two class constructors, one without
arguments and one with two arguments.

class CoOrds
{
public int x, y;

// Default constructor:
public CoOrds()
{
x = 0;
y = 0;
}

// tcA constructor with two arguments:


public CoOrds(int x, int y)
{
this.x = x;
this.y = y;
}
// Override the ToString method:
public override string ToString()
{
return (String.Format("({0},{1})", x, y));
}
}

class MainClass
{
static void Main()
{
CoOrds p1 = new CoOrds();
CoOrds p2 = new CoOrds(5, 3);

// Display the results using the overriden ToString method:


Console.WriteLine("CoOrds #1 at {0}", p1);
Console.WriteLine("CoOrds #2 at {0}", p2);
Console.ReadKey();
}
}
/* Output:
CoOrds #1 at (0,0)
CoOrds #2 at (5,3)
*/

Example 2
In this example, the class Person does not have any constructors, in which case, a default
constructor is automatically provided and the fields are initialized to their default values.

public class Person


{
public int age;
public string name;
}

class TestPerson
{
static void Main()
{
Person person = new Person();

Console.WriteLine("Name: {0}, Age: {1}", person.name, person.age);


// Keep the console window open in debug mode.
Console.WriteLine("Press any key to exit.");
Console.ReadKey();
}
}
// Output: Name: , Age: 0

Notice that the default value of age is 0 and the default value of name is null. For more
information on default values, see Default Values Table (C# Reference).

Example 3
The following example demonstrates using the base class initializer. The Circle class is
derived from the general class Shape, and the Cylinder class is derived from the Circle
class. The constructor on each derived class is using its base class initializer.

abstract class Shape


{
public const double pi = Math.PI;
protected double x, y;

public Shape(double x, double y)


{
this.x = x;
this.y = y;
}

public abstract double Area();


}

class Circle : Shape


{
public Circle(double radius)
: base(radius, 0)
{
}
public override double Area()
{
return pi * x * x;
}
}

class Cylinder : Circle


{
public Cylinder(double radius, double height)
: base(radius)
{
y = height;
}

public override double Area()


{
return (2 * base.Area()) + (2 * pi * x * y);
}
}

class TestShapes
{
static void Main()
{
double radius = 2.5;
double height = 3.0;

Circle ring = new Circle(radius);


Cylinder tube = new Cylinder(radius, height);

Console.WriteLine("Area of the circle = {0:F2}", ring.Area());


Console.WriteLine("Area of the cylinder = {0:F2}", tube.Area());

// Keep the console window open in debug mode.


Console.WriteLine("Press any key to exit.");
Console.ReadKey();
}
}
/* Output:
Area of the circle = 19.63
Area of the cylinder = 86.39
*/

Private Constructors
A private constructor is a special instance constructor. It is generally used in classes that
contain static members only. If a class has one or more private constructors and no public
constructors, other classes (except nested classes) cannot create instances of this class.
For example:

class NLog
{
// Private Constructor:
private NLog() { }

public static double e = Math.E; //2.71828...


}

The declaration of the empty constructor prevents the automatic generation of a default
constructor. Note that if you do not use an access modifier with the constructor it will still
be private by default. However, the private modifier is usually used explicitly to make it
clear that the class cannot be instantiated.
Private constructors are used to prevent creating instances of a class when there are no
instance fields or methods, such as the Math class, or when a method is called to obtain
an instance of a class. If all the methods in the class are static, consider making the
complete class static. For more information see Static Classes and Static Class Members
(C# Programming Guide).

Example
The following is an example of a class using a private constructor.

public class Counter


{
private Counter() { }
public static int currentCount;
public static int IncrementCount()
{
return ++currentCount;
}
}

class TestCounter
{
static void Main()
{
// If you uncomment the following statement, it will generate
// an error because the constructor is inaccessible:
// Counter aCounter = new Counter(); // Error

Counter.currentCount = 100;
Counter.IncrementCount();
Console.WriteLine("New count: {0}", Counter.currentCount);

// Keep the console window open in debug mode.


Console.WriteLine("Press any key to exit.");
Console.ReadKey();
}
}
// Output: New count: 101

Notice that if you uncomment the following statement from the example, it will generate
an error because the constructor is inaccessible because of its protection level:

// Counter aCounter = new Counter(); // Error

Static Constructors
A static constructor is used to initialize any static data, or to perform a particular action
that needs performed once only. It is called automatically before the first instance is
created or any static members are referenced.

class SimpleClass
{
// Static variable that must be initialized at run time.
static readonly long baseline;

// Static constructor is called at most one time, before any


// instance constructor is invoked or member is accessed.
static SimpleClass()
{
baseline = DateTime.Now.Ticks;
}
}

Static constructors have the following properties:

A static constructor does not take access modifiers or have parameters.

A static constructor is called automatically to initialize the class before the first instance is
created or any static members are referenced.

A static constructor cannot be called directly.

The user has no control on when the static constructor is executed in the program.

A typical use of static constructors is when the class is using a log file and the constructor
is used to write entries to this file.

Static constructors are also useful when creating wrapper classes for unmanaged code,
when the constructor can call the LoadLibrary method.

If a static constructor throws an exception, the runtime will not invoke it a second time,
and the type will remain uninitialized for the lifetime of the application domain in which
your program is running.

Example
In this example, the class Bus has a static constructor and one static member, Drive().
When Drive() is called, the static constructor is invoked to initialize the class.

public class Bus


{
// static variable used by all Bus instances
// Represents the time the first bus of the day starts its route.
protected static readonly DateTime globalStartTime;

// Instance readonly variable


protected int RouteNumber { get; set; }

// Static constructor to initialize static variable.


// It is invoked before the first instance constructor is called.
static Bus()
{
globalStartTime = DateTime.Now;
Console.WriteLine("Static ctor sets global start time to {0}",
globalStartTime.ToLongTimeString());
}

// Instance constructor
public Bus(int routeNum)
{
RouteNumber = routeNum;
Console.WriteLine("{0} is created.", RouteNumber);
}

// Instance method.
public void Drive()
{
TimeSpan elapsedTime = DateTime.Now - globalStartTime;

// For demonstration purposes we treat milliseconds as minutes to


// simulate actual bus times. Do not do this in your actual bus schedule program!
Console.WriteLine("{0} is starting its route {1:N2} minutes after global start time
{2}.",
this.RouteNumber,
elapsedTime.TotalMilliseconds,
globalStartTime.ToShortTimeString());
}
}

class TestBus
{
static void Main()
{

Bus bus = new Bus(71);


bus.Drive();

// Wait for next bus to warm up.


System.Threading.Thread.Sleep(25);
Bus bus2 = new Bus(72);
bus2.Drive();

// Keep the console window open in debug mode.


System.Console.WriteLine("Press any key to exit.");
System.Console.ReadKey();
}
}
/* Output:
Static ctor sets global start time to 10:04:08 AM
71 is created.
71 is starting its route 21.00 minutes after global start time 10:04 AM.
72 is created.
72 is starting its route 46.00 minutes after global start time 10:04 AM.
*/

Using Constructors

Constructors are class methods that are executed when an object of a given type is
created. Constructors have the same name as the class, and usually initialize the data
members of the new object.

In the following example, a class named Taxi is defined by using a simple constructor.
This class is then instantiated with the new operator. The Taxi constructor is invoked by
the new operator immediately after memory is allocated for the new object.

public class Taxi


{
public bool isInitialized;
public Taxi()
{
isInitialized = true;
}
}

class TestTaxi
{
static void Main()
{
Taxi t = new Taxi();
Console.WriteLine(t.isInitialized);
}
}
A constructor that takes no parameters is called a default constructor. Default
constructors are invoked whenever an object is instantiated by using the new operator
and no arguments are provided to new. For more information, see Instance Constructors
(C# Programming Guide).

Unless the class is static, classes without constructors are given a public default
constructor by the C# compiler in order to enable class instantiation. For more
information, see Static Classes and Static Class Members (C# Programming Guide).

You can prevent a class from being instantiated by making the constructor private, as
follows:

class NLog
{
// Private Constructor:
private NLog() { }

public static double e = Math.E; //2.71828...


}

For more information, see Private Constructors (C# Programming Guide).

Constructors for struct types resemble class constructors, but structs cannot contain an
explicit default constructor because one is provided automatically by the compiler. This
constructor initializes each field in the struct to the default values. For more information,
see Default Values Table (C# Reference). However, this default constructor is only
invoked if the struct is instantiated with new. For example, this code uses the default
constructor for Int32, so that you are assured that the integer is initialized:

int i = new int();


Console.WriteLine(i);
The following code, however, causes Compiler Error CS0165 because it does not use new,
and because it tries to use an object that has not been initialized:

int i;
Console.WriteLine(i);
Alternatively, objects based on structs (including all built-in numeric types) can be
initialized or assigned and then used as in the following example:

int a = 44; // Initialize the value type...


int b;
b = 33; // Or assign it before using it.
Console.WriteLine("{0}, {1}", a, b);
So calling the default constructor for a value type is not required.
Both classes and structs can define constructors that take parameters. Constructors that
take parameters must be called through a new statement or a base statement. Classes
and structs can also define multiple constructors, and neither is required to define a
default constructor. For example:

public class Employee


{
public int salary;

public Employee(int annualSalary)


{
salary = annualSalary;
}

public Employee(int weeklySalary, int numberOfWeeks)


{
salary = weeklySalary * numberOfWeeks;
}
}

This class can be created by using either of the following statements:

Employee e1 = new Employee(30000);


Employee e2 = new Employee(500, 52);

A constructor can use the base keyword to call the constructor of a base class. For
example:

public class Manager : Employee


{
public Manager(int annualSalary)
: base(annualSalary)
{
//Add further instructions here.
}
}

In this example, the constructor for the base class is called before the block for the
constructor is executed. The base keyword can be used with or without parameters. Any
parameters to the constructor can be used as parameters to base, or as part of an
expression. For more information, see base (C# Reference).

In a derived class, if a base-class constructor is not called explicitly by using the base
keyword, the default constructor, if there is one, is called implicitly. This means that the
following constructor declarations are effectively the same:
public Manager(int initialdata)
{
//Add further instructions here.
}

public Manager(int initialdata)


: base()
{
//Add further instructions here.
}

If a base class does not offer a default constructor, the derived class must make an
explicit call to a base constructor by using base.

A constructor can invoke another constructor in the same object by using the this
keyword. Like base, this can be used with or without parameters, and any parameters in
the constructor are available as parameters to this, or as part of an expression. For
example, the second constructor in the previous example can be rewritten using this:

public Employee(int weeklySalary, int numberOfWeeks)


: this(weeklySalary * numberOfWeeks)
{
}

The use of the this keyword in the previous example causes this constructor to be called:

public Employee(int annualSalary)


{
salary = annualSalary;
}

Constructors can be marked as public, private, protected, internal, or protected internal.


These access modifiers define how users of the class can construct the class. For more
information, see Access Modifiers.

A constructor can be declared static by using the static keyword. Static constructors are
called automatically, immediately before any static fields are accessed, and are generally
used to initialize static class members

Copy Constructors
Copying a class
C# does not provide a copy constructor. If you create a new object and want to copy the
values from an existing object, you have to write the appropriate method yourself. For
example:

class Car
{
private string plate;
private int mileage;

// Copy constructor.
public Car(Car previousCar)
{
plate = previousCar.plate;
mileage = previousCar.mileage;
}

// Instance constructor.
public Car(string plate, int mileage)
{
this.plate = plate;
this.mileage = mileage;
}

// Get accessor.
public string Details
{
get
{
return "The car : " + plate + " has done "
+ mileage.ToString() + " miles";
}
}
}

class TestCar
{
static void Main()
{
// Create a new car object.
Car car1 = new Car("BB06 YUK", 40000);

// Create another new object, copying car1.


Car car2 = new Car(car1);
System.Console.WriteLine(car2.Details);
}
}
An alternative
This is a simple way to copy an object; however, an alternative method is to implement
the ICloneable interface.

How to: Write a Copy Constructor (C# Programming Guide)

Unlike some languages, C# does not provide a copy constructor. If you create a new
object and want to copy the values from an existing object, you have to write the
appropriate method yourself.

Example
In this example, the Person class contains a constructor that takes as the argument
another object of type Person. The contents of the fields in this object are then assigned
to the fields in the new object.

class Person
{
private string name;
private int age;

// Copy constructor.
public Person(Person previousPerson)
{
name = previousPerson.name;
age = previousPerson.age;
}

// Instance constructor.
public Person(string name, int age)
{
this.name = name;
this.age = age;
}

// Get accessor.
public string Details
{
get
{
return name + " is " + age.ToString();
}
}
}

class TestPerson
{
static void Main()
{
// Create a new person object.
Person person1 = new Person("George", 40);

// Create another new object, copying person.


Person person2 = new Person(person1);
Console.WriteLine(person2.Details);

// Keep the console window open in debug mode.


Console.WriteLine("Press any key to exit.");
Console.ReadKey();
}
}
// Output: George is 40

Declaring Classes
A class is an abstract representation for some particular type of object. It can be
described as a template or blueprint for an object, as opposed to the actual object itself.
Thus, objects are an instance of a class - they come into existence at some specific time,
persist for some duration, and then disappear when they are no longer needed. Classes
are the abstract descriptions used by the system to create objects when called upon to do
so.

Declaration
[attributes] [modifiers] class identifier [:base-type]
{
body [;]
}The attributes is optional and is used to hold additional declarative information.

The modifier is optional. The allowed modifiers are static, sealed, abstract, unsafe, public
and internal. If no modifier is supplied then a default of internal is used.

The keyword class must be followed by an identifier that names the class.

base-type may define any class other than System.Array, System.Delegate,


System.MulticastDelegate, System.Enum or System.ValueType as the base class for this
class. If a base class is not supplied, then the class will inherit from System.Object.

base-type may also specify the interfaces implemented by this class. The interfaces must
be listed after the base class name (if specified) and must be separated by commas.

The body contains the member declarations.

[edit]A simple class


The following code contains the minimum code for a class. Although this class will not
actually do anything.
class SimpleObject
{
public SimpleObject()
{
}
}

Modifiers
abstract - the class is created solely for the purpose of inheritance. You cannot create an
instance of an abstract class.

sealed - the class cannot be inherited from.

static – the class can only contain static members.

unsafe - allows for unsafe constructs such as pointers. Requires the unsafe compiler
option.

public - any item in the current assembly or any assembly that references it, can access
this class.

internal - Any item in the current assembly can access this class.

The access levels protected and private are only allowed on nested classes.

Abstract and Sealed Classes and Class Members

The abstract keyword enables you to create classes and class members that are
incomplete and must be implemented in a derived class.

The sealed keyword enables you to prevent the inheritance of a class or certain class
members that were previously marked virtual.

Abstract Classes and Class Members


Classes can be declared as abstract by putting the keyword abstract before the class
definition. For example:

public abstract class A


{
// Class members here.
}

An abstract class cannot be instantiated. The purpose of an abstract class is to provide a


common definition of a base class that multiple derived classes can share. For example, a
class library may define an abstract class that is used as a parameter to many of its
functions, and require programmers using that library to provide their own
implementation of the class by creating a derived class.
Abstract classes may also define abstract methods. This is accomplished by adding the
keyword abstract before the return type of the method. For example:

public abstract class A


{
public abstract void DoWork(int i);
}

Abstract methods have no implementation, so the method definition is followed by a


semicolon instead of a normal method block. Derived classes of the abstract class must
implement all abstract methods. When an abstract class inherits a virtual method from a
base class, the abstract class can override the virtual method with an abstract method.
For example:

// compile with: /target:library


public class D
{
public virtual void DoWork(int i)
{
// Original implementation.
}
}

public abstract class E : D


{
public abstract override void DoWork(int i);
}

public class F : E
{
public override void DoWork(int i)
{
// New implementation.
}
}

If a virtual method is declared abstract, it is still virtual to any class inheriting from the
abstract class. A class inheriting an abstract method cannot access the original
implementation of the method—in the previous example, DoWork on class F cannot call
DoWork on class D. In this way, an abstract class can force derived classes to provide new
method implementations for virtual methods.

Sealed Classes and Class Members


Classes can be declared as sealed by putting the keyword sealed before the class
definition. For example:
public sealed class D
{
// Class members here.
}

A sealed class cannot be used as a base class. For this reason, it cannot also be an
abstract class. Sealed classes prevent derivation. Because they can never be used as a
base class, some run-time optimizations can make calling sealed class members slightly
faster.

A class member, method, field, property, or event, on a derived class that is overriding a
virtual member of the base class can declare that member as sealed. This negates the
virtual aspect of the member for any further derived class. This is accomplished by putting
the sealed keyword before the override keyword in the class member declaration. For
example:

public class D : C
{
public sealed override void DoWork() { }
}

internal
The internal keyword is an access modifier for types and type members. Internal types or
members are accessible only within files in the same assembly, as in this example:

public class BaseClass


{
// Only accessible within the same assembly
internal static int x = 0;
}
For a comparison of internal with the other access modifiers, see Accessibility Levels (C#
Reference) and Access Modifiers (C# Programming Guide).

For more information about assemblies, see Assemblies and the Global Assembly Cache
(C# Programming Guide).

A common use of internal access is in component-based development because it enables a


group of components to cooperate in a private manner without being exposed to the rest
of the application code. For example, a framework for building graphical user interfaces
could provide Control and Form classes that cooperate by using members with internal
access. Since these members are internal, they are not exposed to code that is using the
framework.

It is an error to reference a type or a member with internal access outside the assembly
within which it was defined.
Note:
An internal virtual method can be overridden in some languages, such as textual Microsoft
intermediate language (MSIL) using Ilasm.exe, even though it cannot be overridden by
using C#.

Example
This example contains two files, Assembly1.cs and Assembly1_a.cs. The first file contains
an internal base class, BaseClass. In the second file, an attempt to instantiate BaseClass
will produce an error.

// Assembly1.cs
// Compile with: /target:library
internal class BaseClass
{
public static int intM = 0;
}
// Assembly1_a.cs
// Compile with: /reference:Assembly1.dll
class TestAccess
{
static void Main()
{
BaseClass myBase = new BaseClass(); // CS0122
}
}
In this example, use the same files you used in example 1, and change the accessibility
level of BaseClass to public. Also change the accessibility level of the member IntM to
internal. In this case, you can instantiate the class, but you cannot access the internal
member.

// Assembly2.cs
// Compile with: /target:library
public class BaseClass
{
internal static int intM = 0;
}
// Assembly2_a.cs
// Compile with: /reference:Assembly1.dll
public class TestAccess
{
static void Main()
{
BaseClass myBase = new BaseClass(); // Ok.
BaseClass.intM = 444; // CS0117
}
}
public

The public keyword is an access modifier for types and type members. Public access is the
most permissive access level. There are no restrictions on accessing public members, as in
this example:

class SampleClass
{
public int x; // No access restrictions.
}
See Access Modifiers (C# Programming Guide) and Accessibility Levels (C# Reference) for
more information.

Example
In the following example, two classes are declared, Point and MainClass. The public
members x and y of Point are accessed directly from MainClass.

class PointTest
{
public int x;
public int y;
}

class MainClass4
{
static void Main()
{
PointTest p = new PointTest();
// Direct access to public members:
p.x = 10;
p.y = 15;
Console.WriteLine("x = {0}, y = {1}", p.x, p.y);
}
}
// Output: x = 10, y = 15

If you change the public access level to private or protected, you will get the error
message:

'Point.y' is inaccessible due to its protection level.

unsafe
The unsafe keyword denotes an unsafe context, which is required for any operation
involving pointers. For more information, see Unsafe Code and Pointers (C# Programming
Guide).
You can use the unsafe modifier in the declaration of a type or a member. The entire
textual extent of the type or member is therefore considered an unsafe context. For
example, the following is a method declared with the unsafe modifier:

unsafe static void FastCopy(byte[] src, byte[] dst, int count)


{
// Unsafe context: can use pointers here.
}
The scope of the unsafe context extends from the parameter list to the end of the
method, so pointers can also be used in the parameter list:

unsafe static void FastCopy ( byte* ps, byte* pd, int count ) {...}
You can also use an unsafe block to enable the use of an unsafe code inside this block. For
example:

unsafe
{
// Unsafe context: can use pointers here.
}
To compile unsafe code, you must specify the /unsafe compiler option. Unsafe code is not
verifiable by the common language runtime.

Example
// compile with: /unsafe

class UnsafeTest
{
// Unsafe method: takes pointer to int:
unsafe static void SquarePtrParam(int* p)
{
*p *= *p;
}

unsafe static void Main()


{
int i = 5;
// Unsafe method: uses address-of operator (&):
SquarePtrParam(&i);
Console.WriteLine(i);
}
}
// Output: 25

Unsafe Code and Pointers


To maintain type safety and security, C# does not support pointer arithmetic, by default.
However, by using the unsafe keyword, you can define an unsafe context in which
pointers can be used. For more information about pointers, see the topic Pointer types.

Note:
In the common language runtime (CLR), unsafe code is referred to as unverifiable code.
Unsafe code in C# is not necessarily dangerous; it is just code whose safety cannot be
verified by the CLR. The CLR will therefore only execute unsafe code if it is in a fully
trusted assembly. If you use unsafe code, it is your responsibility to ensure that your code
does not introduce security risks or pointer errors. For more information, see Security (C#
Programming Guide).

Unsafe Code Overview


Unsafe code has the following properties:

Methods, types, and code blocks can be defined as unsafe.

In some cases, unsafe code may increase an application's performance by removing array
bounds checks.

Unsafe code is required when you call native functions that require pointers.

Using unsafe code introduces security and stability risks.

In order for C# to compile unsafe code, the application must be compiled with /unsafe.

Delegate
Summary
A delegate is basically a reference to a method. A delegate can be passed like any other
variable. This allows the method to be called anonymously, without calling the method
directly.

In C#, delegates are the basis for events.

For example:

A object can create a delegate that refers to one of its private methods. Then the object
can pass that delegate to another object. The second object could then call that private
method without knowing anything about it (loose-binding).

Code Examples
These examples demonstrate delegates that are not used for events

Naming convention used in these Code Examples:

Name delegate types with a suffix of "Callback"


Name delegate instances with a previx of "do"

do stands for both "do something" and "delegate object"

Example Names:

// Delegate Declaration
public delegate void AcceptCallback();

// Delegate Instance
AcceptCallback doAccept;
Declare a void delegate that takes no parameters:

public delegate void ExecuteCallback();Declare a delegate that has parameters and


returns a value:

public delegate int AccountComparisonCallback( Account a, Account b );Declare a generic


delegate that has parameters and returns a value:

public delegate int CompareCallback<T>( T a, T b );Create a delegate object that refers to


a method called Compare:

AccountComparisonCallback doComparison = new


AccountComparisonCallback( Compare );Call a delegate

// (Outside the class)


// The delegate type declaration
public delegate int AccountComparisonCallback( Account a, Account b );

// (Inside the class)


// The delegate instance
private AccountComparisonCallback _doComparison;

// This method calls the comparison delegate safely


// Which simplifies the call so other class methods
// can easily call the delegate
private int CallComparison( Account a, Account b )
{
// Check for null before calling a delegate
if( _doComparison != null )
{
// Call the delegate like a method
return _doComparison( a, b );
}
// If the delegate is null, return 0
else
{
return 0;
}
}
Create a delegate object and pass it as a parameter

// The AccountComparison Delegate


public delegate int AccountComparisonCallback( Account a, Account b );

public class AccountSorter


{
// Declare a method that has the same signature as the delegate
private int Compare( Account a, Account b )
{
// ...
}

// Declare a method that uses the delegate


public void Sort( List<Account> accounts )
{
// Create the delegate object that refers to the Compare method
AccountComparisonCallback doComparison = new
AccountComparisonCallback( Compare );

// Pass the delegate as an argument to a method


accounts.Sort( doComparison );

// Explaination:
// Inside the Sort method, the delegate will be called
// which calls the private Compare method to which it refers
// In this way the Sort method is able to call a method without
// knowing anything about the actual method
}
}

DictionaryBase classes

DictionaryBase Class

Provides the abstract base class for a strongly typed collection of key/value pairs.

Namespace: System.Collections
Assembly: mscorlib (in mscorlib.dll)
Syntax
Visual Basic (Declaration)
<SerializableAttribute> _
<ComVisibleAttribute(True)> _
Public MustInherit Class DictionaryBase _
Implements IDictionary, ICollection, IEnumerable
Visual Basic (Usage)
Dim instance As DictionaryBase
C#
[SerializableAttribute]
[ComVisibleAttribute(true)]
public abstract class DictionaryBase : IDictionary,
ICollection, IEnumerable

Remarks
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 DictionaryBase 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 myDictionary) {...}

Visual Basic Copy Code


For Each de As Dictionary Entry In myDictionary
...
Next myDE

vb#c#
The foreach statement is a wrapper around the enumerator, which only allows reading
from, not writing to, the collection.

Note:
Because keys can be inherited and their behavior changed, their absolute uniqueness
cannot be guaranteed by comparisons using the Equals method.

Notes to Implementers:
This base class is provided to make it easier for implementers to create a strongly typed
custom collection. Implementers are encouraged to extend this base class instead of
creating their own.

Members of this base class are protected and are intended to be used through a derived
class only.

Examples
The following code example implements the DictionaryBase class and uses that
implementation to create a dictionary of String keys and values that have a Length of 5
characters or less.
Visual Basic Copy Code
Imports System
Imports System.Collections

Public Class ShortStringDictionary


Inherits DictionaryBase

Default Public Property Item(key As String) As String


Get
Return CType(Dictionary(key), String)
End Get
Set
Dictionary(key) = value
End Set
End Property

Public ReadOnly Property Keys() As ICollection


Get
Return Dictionary.Keys
End Get
End Property

Public ReadOnly Property Values() As ICollection


Get
Return Dictionary.Values
End Get
End Property

Public Sub Add(key As String, value As String)


Dictionary.Add(key, value)
End Sub 'Add

Public Function Contains(key As String) As Boolean


Return Dictionary.Contains(key)
End Function 'Contains

Public Sub Remove(key As String)


Dictionary.Remove(key)
End Sub 'Remove

Protected Overrides Sub OnInsert(key As Object, value As Object)


If Not GetType(System.String).IsAssignableFrom(key.GetType()) Then
Throw New ArgumentException("key must be of type String.", "key")
Else
Dim strKey As String = CType(key, String)
If strKey.Length > 5 Then
Throw New ArgumentException("key must be no more than 5 characters in
length.", "key")
End If
End If
If Not GetType(System.String).IsAssignableFrom(value.GetType()) Then
Throw New ArgumentException("value must be of type String.", "value")
Else
Dim strValue As String = CType(value, String)
If strValue.Length > 5 Then
Throw New ArgumentException("value must be no more than 5 characters in
length.", "value")
End If
End If
End Sub 'OnInsert

Protected Overrides Sub OnRemove(key As Object, value As Object)


If Not GetType(System.String).IsAssignableFrom(key.GetType()) Then
Throw New ArgumentException("key must be of type String.", "key")
Else
Dim strKey As String = CType(key, String)
If strKey.Length > 5 Then
Throw New ArgumentException("key must be no more than 5 characters in
length.", "key")
End If
End If
End Sub 'OnRemove

Protected Overrides Sub OnSet(key As Object, oldValue As Object, newValue As Object)


If Not GetType(System.String).IsAssignableFrom(key.GetType()) Then
Throw New ArgumentException("key must be of type String.", "key")
Else
Dim strKey As String = CType(key, String)
If strKey.Length > 5 Then
Throw New ArgumentException("key must be no more than 5 characters in
length.", "key")
End If
End If
If Not GetType(System.String).IsAssignableFrom(newValue.GetType()) Then
Throw New ArgumentException("newValue must be of type String.", "newValue")
Else
Dim strValue As String = CType(newValue, String)
If strValue.Length > 5 Then
Throw New ArgumentException("newValue must be no more than 5 characters in
length.", "newValue")
End If
End If
End Sub 'OnSet
Protected Overrides Sub OnValidate(key As Object, value As Object)
If Not GetType(System.String).IsAssignableFrom(key.GetType()) Then
Throw New ArgumentException("key must be of type String.", "key")
Else
Dim strKey As String = CType(key, String)
If strKey.Length > 5 Then
Throw New ArgumentException("key must be no more than 5 characters in
length.", "key")
End If
End If
If Not GetType(System.String).IsAssignableFrom(value.GetType()) Then
Throw New ArgumentException("value must be of type String.", "value")
Else
Dim strValue As String = CType(value, String)
If strValue.Length > 5 Then
Throw New ArgumentException("value must be no more than 5 characters in
length.", "value")
End If
End If
End Sub 'OnValidate

End Class 'ShortStringDictionary

Public Class SamplesDictionaryBase

Public Shared Sub Main()

' Creates and initializes a new DictionaryBase.


Dim mySSC As New ShortStringDictionary()

' Adds elements to the collection.


mySSC.Add("One", "a")
mySSC.Add("Two", "ab")
mySSC.Add("Three", "abc")
mySSC.Add("Four", "abcd")
mySSC.Add("Five", "abcde")

' Display the contents of the collection using For Each. This is the preferred method.
Console.WriteLine("Contents of the collection (using For Each):")
PrintKeysAndValues1(mySSC)

' Display the contents of the collection using the enumerator.


Console.WriteLine("Contents of the collection (using enumerator):")
PrintKeysAndValues2(mySSC)

' Display the contents of the collection using the Keys property and the Item property.
Console.WriteLine("Initial contents of the collection (using Keys and Item):")
PrintKeysAndValues3(mySSC)

' Tries to add a value that is too long.


Try
mySSC.Add("Ten", "abcdefghij")
Catch e As ArgumentException
Console.WriteLine(e.ToString())
End Try

' Tries to add a key that is too long.


Try
mySSC.Add("Eleven", "ijk")
Catch e As ArgumentException
Console.WriteLine(e.ToString())
End Try

Console.WriteLine()

' Searches the collection with Contains.


Console.WriteLine("Contains ""Three"": {0}", mySSC.Contains("Three"))
Console.WriteLine("Contains ""Twelve"": {0}", mySSC.Contains("Twelve"))
Console.WriteLine()

' Removes an element from the collection.


mySSC.Remove("Two")

' Displays the contents of the collection.


Console.WriteLine("After removing ""Two"":")
PrintKeysAndValues1(mySSC)

End Sub 'Main

' Uses the For Each statement which hides the complexity of the enumerator.
' NOTE: The For Each statement is the preferred way of enumerating the contents of a
collection.
Public Shared Sub PrintKeysAndValues1(myCol As ShortStringDictionary)
Dim myDE As DictionaryEntry
For Each myDE In myCol
Console.WriteLine(" {0,-5} : {1}", myDE.Key, myDE.Value)
Next myDE
Console.WriteLine()
End Sub 'PrintKeysAndValues1

' Uses the enumerator.


' NOTE: The For Each statement is the preferred way of enumerating the contents of a
collection.
Public Shared Sub PrintKeysAndValues2(myCol As ShortStringDictionary)
Dim myDE As DictionaryEntry
Dim myEnumerator As System.Collections.IEnumerator = myCol.GetEnumerator()
While myEnumerator.MoveNext()
If Not (myEnumerator.Current Is Nothing) Then
myDE = CType(myEnumerator.Current, DictionaryEntry)
Console.WriteLine(" {0,-5} : {1}", myDE.Key, myDE.Value)
End If
End While
Console.WriteLine()
End Sub 'PrintKeysAndValues2

' Uses the Keys property and the Item property.


Public Shared Sub PrintKeysAndValues3(myCol As ShortStringDictionary)
Dim myKeys As ICollection = myCol.Keys
Dim k As String
For Each k In myKeys
Console.WriteLine(" {0,-5} : {1}", k, myCol(k))
Next k
Console.WriteLine()
End Sub 'PrintKeysAndValues3

End Class 'SamplesDictionaryBase

'This code produces the following output.


'
'Contents of the collection (using For Each):
' Three : abc
' Five : abcde
' Two : ab
' One : a
' Four : abcd
'
'Contents of the collection (using enumerator):
' Three : abc
' Five : abcde
' Two : ab
' One : a
' Four : abcd
'
'Initial contents of the collection (using Keys and Item):
' Three : abc
' Five : abcde
' Two : ab
' One : a
' Four : abcd
'
'System.ArgumentException: value must be no more than 5 characters in length.
'Parameter name: value
' at ShortStringDictionary.OnValidate(Object key, Object value)
' at System.Collections.DictionaryBase.System.Collections.IDictionary.Add(Object key,
Object value)
' at SamplesDictionaryBase.Main()
'System.ArgumentException: key must be no more than 5 characters in length.
'Parameter name: key
' at ShortStringDictionary.OnValidate(Object key, Object value)
' at System.Collections.DictionaryBase.System.Collections.IDictionary.Add(Object key,
Object value)
' at SamplesDictionaryBase.Main()
'
'Contains "Three": True
'Contains "Twelve": False
'
'After removing "Two":
' Three : abc
' Five : abcde
' One : a
' Four : abcd

C#
using System;
using System.Collections;

public class ShortStringDictionary : DictionaryBase {

public String this[ String key ] {


get {
return( (String) Dictionary[key] );
}
set {
Dictionary[key] = value;
}
}

public ICollection Keys {


get {
return( Dictionary.Keys );
}
}
public ICollection Values {
get {
return( Dictionary.Values );
}
}

public void Add( String key, String value ) {


Dictionary.Add( key, value );
}

public bool Contains( String key ) {


return( Dictionary.Contains( key ) );
}

public void Remove( String key ) {


Dictionary.Remove( key );
}

protected override void OnInsert( Object key, Object value ) {


if ( key.GetType() != typeof(System.String) )
throw new ArgumentException( "key must be of type String.", "key" );
else {
String strKey = (String) key;
if ( strKey.Length > 5 )
throw new ArgumentException( "key must be no more than 5 characters in
length.", "key" );
}

if ( value.GetType() != typeof(System.String) )
throw new ArgumentException( "value must be of type String.", "value" );
else {
String strValue = (String) value;
if ( strValue.Length > 5 )
throw new ArgumentException( "value must be no more than 5 characters in
length.", "value" );
}
}

protected override void OnRemove( Object key, Object value ) {


if ( key.GetType() != typeof(System.String) )
throw new ArgumentException( "key must be of type String.", "key" );
else {
String strKey = (String) key;
if ( strKey.Length > 5 )
throw new ArgumentException( "key must be no more than 5 characters in
length.", "key" );
}
}

protected override void OnSet( Object key, Object oldValue, Object newValue ) {
if ( key.GetType() != typeof(System.String) )
throw new ArgumentException( "key must be of type String.", "key" );
else {
String strKey = (String) key;
if ( strKey.Length > 5 )
throw new ArgumentException( "key must be no more than 5 characters in
length.", "key" );
}

if ( newValue.GetType() != typeof(System.String) )
throw new ArgumentException( "newValue must be of type String.", "newValue" );
else {
String strValue = (String) newValue;
if ( strValue.Length > 5 )
throw new ArgumentException( "newValue must be no more than 5 characters in
length.", "newValue" );
}
}

protected override void OnValidate( Object key, Object value ) {


if ( key.GetType() != typeof(System.String) )
throw new ArgumentException( "key must be of type String.", "key" );
else {
String strKey = (String) key;
if ( strKey.Length > 5 )
throw new ArgumentException( "key must be no more than 5 characters in
length.", "key" );
}

if ( value.GetType() != typeof(System.String) )
throw new ArgumentException( "value must be of type String.", "value" );
else {
String strValue = (String) value;
if ( strValue.Length > 5 )
throw new ArgumentException( "value must be no more than 5 characters in
length.", "value" );
}
}

public class SamplesDictionaryBase {


public static void Main() {

// Creates and initializes a new DictionaryBase.


ShortStringDictionary mySSC = new ShortStringDictionary();

// Adds elements to the collection.


mySSC.Add( "One", "a" );
mySSC.Add( "Two", "ab" );
mySSC.Add( "Three", "abc" );
mySSC.Add( "Four", "abcd" );
mySSC.Add( "Five", "abcde" );

// Display the contents of the collection using foreach. This is the preferred method.
Console.WriteLine( "Contents of the collection (using foreach):" );
PrintKeysAndValues1( mySSC );

// Display the contents of the collection using the enumerator.


Console.WriteLine( "Contents of the collection (using enumerator):" );
PrintKeysAndValues2( mySSC );

// Display the contents of the collection using the Keys property and the Item
property.
Console.WriteLine( "Initial contents of the collection (using Keys and Item):" );
PrintKeysAndValues3( mySSC );

// Tries to add a value that is too long.


try {
mySSC.Add( "Ten", "abcdefghij" );
}
catch ( ArgumentException e ) {
Console.WriteLine( e.ToString() );
}

// Tries to add a key that is too long.


try {
mySSC.Add( "Eleven", "ijk" );
}
catch ( ArgumentException e ) {
Console.WriteLine( e.ToString() );
}

Console.WriteLine();

// Searches the collection with Contains.


Console.WriteLine( "Contains \"Three\": {0}", mySSC.Contains( "Three" ) );
Console.WriteLine( "Contains \"Twelve\": {0}", mySSC.Contains( "Twelve" ) );
Console.WriteLine();
// Removes an element from the collection.
mySSC.Remove( "Two" );

// Displays the contents of the collection.


Console.WriteLine( "After removing \"Two\":" );
PrintKeysAndValues1( mySSC );

// Uses the foreach statement which hides the complexity of the enumerator.
// NOTE: The foreach statement is the preferred way of enumerating the contents of a
collection.
public static void PrintKeysAndValues1( ShortStringDictionary myCol ) {
foreach ( DictionaryEntry myDE in myCol )
Console.WriteLine( " {0,-5} : {1}", myDE.Key, myDE.Value );
Console.WriteLine();
}

// Uses the enumerator.


// NOTE: The foreach statement is the preferred way of enumerating the contents of a
collection.
public static void PrintKeysAndValues2( ShortStringDictionary myCol ) {
DictionaryEntry myDE;
System.Collections.IEnumerator myEnumerator = myCol.GetEnumerator();
while ( myEnumerator.MoveNext() )
if ( myEnumerator.Current != null ) {
myDE = (DictionaryEntry) myEnumerator.Current;
Console.WriteLine( " {0,-5} : {1}", myDE.Key, myDE.Value );
}
Console.WriteLine();
}

// Uses the Keys property and the Item property.


public static void PrintKeysAndValues3( ShortStringDictionary myCol ) {
ICollection myKeys = myCol.Keys;
foreach ( String k in myKeys )
Console.WriteLine( " {0,-5} : {1}", k, myCol[k] );
Console.WriteLine();
}

/*
This code produces the following output.

Contents of the collection (using foreach):


Three : abc
Five : abcde
Two : ab
One : a
Four : abcd

Contents of the collection (using enumerator):


Three : abc
Five : abcde
Two : ab
One : a
Four : abcd

Initial contents of the collection (using Keys and Item):


Three : abc
Five : abcde
Two : ab
One : a
Four : abcd

System.ArgumentException: value must be no more than 5 characters in length.


Parameter name: value
at ShortStringDictionary.OnValidate(Object key, Object value)
at System.Collections.DictionaryBase.System.Collections.IDictionary.Add(Object key,
Object value)
at SamplesDictionaryBase.Main()
System.ArgumentException: key must be no more than 5 characters in length.
Parameter name: key
at ShortStringDictionary.OnValidate(Object key, Object value)
at System.Collections.DictionaryBase.System.Collections.IDictionary.Add(Object key,
Object value)
at SamplesDictionaryBase.Main()

Contains "Three": True


Contains "Twelve": False

After removing "Two":


Three : abc
Five : abcde
One : a
Four : abcd

*/

Вам также может понравиться